<commit_before>extern crate log;

use std::io::{Write, stderr};
use std::sync::Mutex;

use log::{Log, LogLevelFilter, LogMetadata, LogRecord, SetLoggerError};

pub struct Writer(pub Box<Write + Send>);

struct Logger {
    writers: Mutex<Vec<Writer>>,
}

impl Log for Logger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, rec: &LogRecord) {
        let mut writers = match self.writers.lock() {
            Ok(writers) => writers,
            Err(err) => {
                let _ = writeln!(stderr(), "{:?}", err);
                return;
            },
        };
        let loc = rec.location();
        for i in 0..writers.len() {
            let _ = writeln!(
                writers[i].0,
                "{}:{}:{}:{}:\t{}",
                loc.module_path(), loc.file(), loc.line(),
                rec.level(), rec.args());
        }
    }
}

pub fn init(writers: Vec<Writer>) -> Result<(), SetLoggerError> {
    log::set_logger(|max_level| {
        max_level.set(LogLevelFilter::max());
        Box::new(Logger {writers: Mutex::new(writers)})
    })
}
<commit_msg>Change logging format<commit_after>extern crate log;

use std::io::{Write, stderr};
use std::sync::Mutex;

use log::{Log, LogLevelFilter, LogMetadata, LogRecord, SetLoggerError};

pub struct Writer(pub Box<Write + Send>);

struct Logger {
    writers: Mutex<Vec<Writer>>,
}

impl Log for Logger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, rec: &LogRecord) {
        let mut writers = match self.writers.lock() {
            Ok(writers) => writers,
            Err(err) => {
                let _ = writeln!(stderr(), "{:?}", err);
                return;
            },
        };
        let loc = rec.location();
        for i in 0..writers.len() {
            let _ = writeln!(
                writers[i].0,
                "{}:{}:{}:\t{}",
                loc.file(), loc.line(), rec.level(), rec.args());
        }
    }
}

pub fn init(writers: Vec<Writer>) -> Result<(), SetLoggerError> {
    log::set_logger(|max_level| {
        max_level.set(LogLevelFilter::max());
        Box::new(Logger {writers: Mutex::new(writers)})
    })
}
<|endoftext|>


<commit_before>#![allow(unsafe_code)]

use std::convert::TryFrom;
use std::ptr;
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};

use crate::{
    debug_delay,
    dll::{DoublyLinkedList, Node},
    fastlock::FastLock,
    Guard, PageId,
    atomic_shim::AtomicU64,
};

#[cfg(any(test, feature = "lock_free_delays"))]
const MAX_QUEUE_ITEMS: usize = 4;

#[cfg(not(any(test, feature = "lock_free_delays")))]
const MAX_QUEUE_ITEMS: usize = 64;

#[cfg(any(test, feature = "lock_free_delays"))]
const N_SHARDS: usize = 2;

#[cfg(not(any(test, feature = "lock_free_delays")))]
const N_SHARDS: usize = 256;

struct AccessBlock {
    len: AtomicUsize,
    block: [AtomicU64; MAX_QUEUE_ITEMS],
    next: AtomicPtr<AccessBlock>,
}

impl Default for AccessBlock {
    fn default() -> AccessBlock {
        AccessBlock {
            len: AtomicUsize::new(0),
            block: array_init::array_init(|_| AtomicU64::default()),
            next: AtomicPtr::default(),
        }
    }
}

struct AccessQueue {
    writing: AtomicPtr<AccessBlock>,
    full_list: AtomicPtr<AccessBlock>,
}

impl Default for AccessQueue {
    fn default() -> AccessQueue {
        AccessQueue {
            writing: AtomicPtr::new(Box::into_raw(Box::new(
                AccessBlock::default(),
            ))),
            full_list: AtomicPtr::default(),
        }
    }
}

impl AccessQueue {
    fn push(&self, item: CacheAccess) -> bool {
        let mut filled = false;
        loop {
            debug_delay();
            let head = self.writing.load(Ordering::Acquire);
            let block = unsafe { &*head };

            debug_delay();
            let offset = block.len.fetch_add(1, Ordering::SeqCst);

            if offset < MAX_QUEUE_ITEMS {
                debug_delay();
                unsafe {
                    block
                        .block
                        .get_unchecked(offset)
                        .store(item.0, Ordering::SeqCst);
                }
                return filled;
            } else {
                // install new writer
                let new = Box::into_raw(Box::new(AccessBlock::default()));
                debug_delay();
                let prev =
                    self.writing.compare_and_swap(head, new, Ordering::SeqCst);
                if prev != head {
                    // we lost the CAS, free the new item that was
                    // never published to other threads
                    unsafe {
                        drop(Box::from_raw(new));
                    }
                    continue;
                }

                // push the now-full item to the full list for future
                // consumption
                let mut ret;
                let mut full_list_ptr = self.full_list.load(Ordering::Acquire);
                while {
                    // we loop because maybe other threads are pushing stuff too
                    block.next.store(full_list_ptr, Ordering::SeqCst);
                    debug_delay();
                    ret = self.full_list.compare_and_swap(
                        full_list_ptr,
                        head,
                        Ordering::SeqCst,
                    );
                    ret != full_list_ptr
                } {
                    full_list_ptr = ret;
                }
                filled = true;
            }
        }
    }

    fn take<'a>(&self, guard: &'a Guard) -> CacheAccessIter<'a> {
        debug_delay();
        let ptr = self.full_list.swap(std::ptr::null_mut(), Ordering::SeqCst);

        CacheAccessIter { guard, current_offset: 0, current_block: ptr }
    }
}

impl Drop for AccessQueue {
    fn drop(&mut self) {
        debug_delay();
        let writing = self.writing.load(Ordering::Acquire);
        unsafe {
            Box::from_raw(writing);
        }
        debug_delay();
        let mut head = self.full_list.load(Ordering::Acquire);
        while !head.is_null() {
            unsafe {
                debug_delay();
                let next =
                    (*head).next.swap(std::ptr::null_mut(), Ordering::SeqCst);
                Box::from_raw(head);
                head = next;
            }
        }
    }
}

struct CacheAccessIter<'a> {
    guard: &'a Guard,
    current_offset: usize,
    current_block: *mut AccessBlock,
}

impl<'a> Iterator for CacheAccessIter<'a> {
    type Item = CacheAccess;

    fn next(&mut self) -> Option<CacheAccess> {
        while !self.current_block.is_null() {
            let current_block = unsafe { &*self.current_block };

            debug_delay();
            if self.current_offset >= MAX_QUEUE_ITEMS {
                let to_drop_ptr = self.current_block;
                debug_delay();
                self.current_block = current_block.next.load(Ordering::Acquire);
                self.current_offset = 0;
                debug_delay();
                let to_drop = unsafe { Box::from_raw(to_drop_ptr) };
                self.guard.defer(|| to_drop);
                continue;
            }

            let mut next = 0;
            while next == 0 {
                // we spin here because there's a race between bumping
                // the offset and setting the value to something other
                // than 0 (and 0 is an invalid value)
                debug_delay();
                next = current_block.block[self.current_offset]
                    .load(Ordering::Acquire);
            }
            self.current_offset += 1;
            return Some(CacheAccess(next));
        }

        None
    }
}

#[derive(Clone, Copy)]
struct CacheAccess(u64);

impl CacheAccess {
    fn new(pid: PageId, sz: u64) -> CacheAccess {
        let rounded_up_power_of_2 =
            u64::from(sz.next_power_of_two().trailing_zeros());

        assert!(rounded_up_power_of_2 < 256);

        CacheAccess(pid | (rounded_up_power_of_2 << 56))
    }

    const fn decompose(self) -> (PageId, u64) {
        let sz = 1 << (self.0 >> 56);
        let pid = self.0 << 8 >> 8;
        (pid, sz)
    }
}

/// A simple LRU cache.
pub struct Lru {
    shards: Vec<(AccessQueue, FastLock<Shard>)>,
}

unsafe impl Sync for Lru {}

impl Lru {
    /// Instantiates a new `Lru` cache.
    pub(crate) fn new(cache_capacity: u64) -> Self {
        assert!(
            cache_capacity >= 256,
            "Please configure the cache \
             capacity to be at least 256 bytes"
        );
        let shard_capacity = cache_capacity / N_SHARDS as u64;

        let mut shards = Vec::with_capacity(N_SHARDS);
        shards.resize_with(N_SHARDS, || {
            (AccessQueue::default(), FastLock::new(Shard::new(shard_capacity)))
        });

        Self { shards }
    }

    /// Called when an item is accessed. Returns a Vec of items to be
    /// evicted. Uses flat-combining to avoid blocking on what can
    /// be an asynchronous operation.
    ///
    /// layout:
    ///   items:   1 2 3 4 5 6 7 8 9 10
    ///   shards:  1 0 1 0 1 0 1 0 1 0
    ///   shard 0:   2   4   6   8   10
    ///   shard 1: 1   3   5   7   9
    pub(crate) fn accessed(
        &self,
        id: PageId,
        item_size: u64,
        guard: &Guard,
    ) -> Vec<PageId> {
        let mut ret = vec![];
        let shards = self.shards.len() as u64;
        let (shard_idx, item_pos) = (id % shards, id / shards);
        let (stack, shard_mu) = &self.shards[safe_usize(shard_idx)];

        let filled = stack.push(CacheAccess::new(item_pos, item_size));

        if filled {
            // only try to acquire this if
            if let Some(mut shard) = shard_mu.try_lock() {
                let accesses = stack.take(guard);
                for item in accesses {
                    let (item_pos, item_size) = item.decompose();
                    let to_evict =
                        shard.accessed(safe_usize(item_pos), item_size);
                    // map shard internal offsets to global items ids
                    for pos in to_evict {
                        let item = (pos * shards) + shard_idx;
                        ret.push(item);
                    }
                }
            }
        }
        ret
    }
}

#[derive(Clone)]
struct Entry {
    ptr: *mut Node,
    size: u64,
}

impl Default for Entry {
    fn default() -> Self {
        Self { ptr: ptr::null_mut(), size: 0 }
    }
}

struct Shard {
    list: DoublyLinkedList,
    entries: Vec<Entry>,
    capacity: u64,
    size: u64,
}

impl Shard {
    fn new(capacity: u64) -> Self {
        assert!(capacity > 0, "shard capacity must be non-zero");

        Self {
            list: DoublyLinkedList::default(),
            entries: vec![],
            capacity,
            size: 0,
        }
    }

    /// `PageId`s in the shard list are indexes of the entries.
    fn accessed(&mut self, pos: usize, size: u64) -> Vec<PageId> {
        if pos >= self.entries.len() {
            self.entries.resize(pos + 1, Entry::default());
        }

        {
            let entry = &mut self.entries[pos];

            self.size -= entry.size;
            entry.size = size;
            self.size += size;

            if entry.ptr.is_null() {
                entry.ptr = self.list.push_head(PageId::try_from(pos).unwrap());
            } else {
                entry.ptr = self.list.promote(entry.ptr);
            }
        }

        let mut to_evict = vec![];
        while self.size > self.capacity {
            if self.list.len() == 1 {
                // don't evict what we just added
                break;
            }

            let min_pid = self.list.pop_tail().unwrap();
            let min_pid_idx = safe_usize(min_pid);

            self.entries[min_pid_idx].ptr = ptr::null_mut();

            to_evict.push(min_pid);

            self.size -= self.entries[min_pid_idx].size;
            self.entries[min_pid_idx].size = 0;
        }

        to_evict
    }
}

#[inline]
fn safe_usize(value: PageId) -> usize {
    usize::try_from(value).unwrap()
}

#[test]
fn lru_smoke_test() {
    use crate::pin;

    let lru = Lru::new(256);
    for i in 0..1000 {
        let guard = pin();
        lru.accessed(i, 16, &guard);
    }
}
<commit_msg>Relax some memory orderings in the LRU<commit_after>#![allow(unsafe_code)]

use std::convert::TryFrom;
use std::ptr;
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};

use crate::{
    atomic_shim::AtomicU64,
    debug_delay,
    dll::{DoublyLinkedList, Node},
    fastlock::FastLock,
    Guard, PageId,
};

#[cfg(any(test, feature = "lock_free_delays"))]
const MAX_QUEUE_ITEMS: usize = 4;

#[cfg(not(any(test, feature = "lock_free_delays")))]
const MAX_QUEUE_ITEMS: usize = 64;

#[cfg(any(test, feature = "lock_free_delays"))]
const N_SHARDS: usize = 2;

#[cfg(not(any(test, feature = "lock_free_delays")))]
const N_SHARDS: usize = 256;

struct AccessBlock {
    len: AtomicUsize,
    block: [AtomicU64; MAX_QUEUE_ITEMS],
    next: AtomicPtr<AccessBlock>,
}

impl Default for AccessBlock {
    fn default() -> AccessBlock {
        AccessBlock {
            len: AtomicUsize::new(0),
            block: array_init::array_init(|_| AtomicU64::default()),
            next: AtomicPtr::default(),
        }
    }
}

struct AccessQueue {
    writing: AtomicPtr<AccessBlock>,
    full_list: AtomicPtr<AccessBlock>,
}

impl Default for AccessQueue {
    fn default() -> AccessQueue {
        AccessQueue {
            writing: AtomicPtr::new(Box::into_raw(Box::new(
                AccessBlock::default(),
            ))),
            full_list: AtomicPtr::default(),
        }
    }
}

impl AccessQueue {
    fn push(&self, item: CacheAccess) -> bool {
        let mut filled = false;
        loop {
            debug_delay();
            let head = self.writing.load(Ordering::Acquire);
            let block = unsafe { &*head };

            debug_delay();
            let offset = block.len.fetch_add(1, Ordering::Release);

            if offset < MAX_QUEUE_ITEMS {
                debug_delay();
                unsafe {
                    block
                        .block
                        .get_unchecked(offset)
                        .store(item.0, Ordering::Release);
                }
                return filled;
            } else {
                // install new writer
                let new = Box::into_raw(Box::new(AccessBlock::default()));
                debug_delay();
                let prev =
                    self.writing.compare_and_swap(head, new, Ordering::Release);
                if prev != head {
                    // we lost the CAS, free the new item that was
                    // never published to other threads
                    unsafe {
                        drop(Box::from_raw(new));
                    }
                    continue;
                }

                // push the now-full item to the full list for future
                // consumption
                let mut ret;
                let mut full_list_ptr = self.full_list.load(Ordering::Acquire);
                while {
                    // we loop because maybe other threads are pushing stuff too
                    block.next.store(full_list_ptr, Ordering::Release);
                    debug_delay();
                    ret = self.full_list.compare_and_swap(
                        full_list_ptr,
                        head,
                        Ordering::Release,
                    );
                    ret != full_list_ptr
                } {
                    full_list_ptr = ret;
                }
                filled = true;
            }
        }
    }

    fn take<'a>(&self, guard: &'a Guard) -> CacheAccessIter<'a> {
        debug_delay();
        let ptr = self.full_list.swap(std::ptr::null_mut(), Ordering::Release);

        CacheAccessIter { guard, current_offset: 0, current_block: ptr }
    }
}

impl Drop for AccessQueue {
    fn drop(&mut self) {
        debug_delay();
        let writing = self.writing.load(Ordering::Acquire);
        unsafe {
            Box::from_raw(writing);
        }
        debug_delay();
        let mut head = self.full_list.load(Ordering::Acquire);
        while !head.is_null() {
            unsafe {
                debug_delay();
                let next =
                    (*head).next.swap(std::ptr::null_mut(), Ordering::Release);
                Box::from_raw(head);
                head = next;
            }
        }
    }
}

struct CacheAccessIter<'a> {
    guard: &'a Guard,
    current_offset: usize,
    current_block: *mut AccessBlock,
}

impl<'a> Iterator for CacheAccessIter<'a> {
    type Item = CacheAccess;

    fn next(&mut self) -> Option<CacheAccess> {
        while !self.current_block.is_null() {
            let current_block = unsafe { &*self.current_block };

            debug_delay();
            if self.current_offset >= MAX_QUEUE_ITEMS {
                let to_drop_ptr = self.current_block;
                debug_delay();
                self.current_block = current_block.next.load(Ordering::Acquire);
                self.current_offset = 0;
                debug_delay();
                let to_drop = unsafe { Box::from_raw(to_drop_ptr) };
                self.guard.defer(|| to_drop);
                continue;
            }

            let mut next = 0;
            while next == 0 {
                // we spin here because there's a race between bumping
                // the offset and setting the value to something other
                // than 0 (and 0 is an invalid value)
                debug_delay();
                next = current_block.block[self.current_offset]
                    .load(Ordering::Acquire);
            }
            self.current_offset += 1;
            return Some(CacheAccess(next));
        }

        None
    }
}

#[derive(Clone, Copy)]
struct CacheAccess(u64);

impl CacheAccess {
    fn new(pid: PageId, sz: u64) -> CacheAccess {
        let rounded_up_power_of_2 =
            u64::from(sz.next_power_of_two().trailing_zeros());

        assert!(rounded_up_power_of_2 < 256);

        CacheAccess(pid | (rounded_up_power_of_2 << 56))
    }

    const fn decompose(self) -> (PageId, u64) {
        let sz = 1 << (self.0 >> 56);
        let pid = self.0 << 8 >> 8;
        (pid, sz)
    }
}

/// A simple LRU cache.
pub struct Lru {
    shards: Vec<(AccessQueue, FastLock<Shard>)>,
}

unsafe impl Sync for Lru {}

impl Lru {
    /// Instantiates a new `Lru` cache.
    pub(crate) fn new(cache_capacity: u64) -> Self {
        assert!(
            cache_capacity >= 256,
            "Please configure the cache \
             capacity to be at least 256 bytes"
        );
        let shard_capacity = cache_capacity / N_SHARDS as u64;

        let mut shards = Vec::with_capacity(N_SHARDS);
        shards.resize_with(N_SHARDS, || {
            (AccessQueue::default(), FastLock::new(Shard::new(shard_capacity)))
        });

        Self { shards }
    }

    /// Called when an item is accessed. Returns a Vec of items to be
    /// evicted. Uses flat-combining to avoid blocking on what can
    /// be an asynchronous operation.
    ///
    /// layout:
    ///   items:   1 2 3 4 5 6 7 8 9 10
    ///   shards:  1 0 1 0 1 0 1 0 1 0
    ///   shard 0:   2   4   6   8   10
    ///   shard 1: 1   3   5   7   9
    pub(crate) fn accessed(
        &self,
        id: PageId,
        item_size: u64,
        guard: &Guard,
    ) -> Vec<PageId> {
        let mut ret = vec![];
        let shards = self.shards.len() as u64;
        let (shard_idx, item_pos) = (id % shards, id / shards);
        let (stack, shard_mu) = &self.shards[safe_usize(shard_idx)];

        let filled = stack.push(CacheAccess::new(item_pos, item_size));

        if filled {
            // only try to acquire this if
            if let Some(mut shard) = shard_mu.try_lock() {
                let accesses = stack.take(guard);
                for item in accesses {
                    let (item_pos, item_size) = item.decompose();
                    let to_evict =
                        shard.accessed(safe_usize(item_pos), item_size);
                    // map shard internal offsets to global items ids
                    for pos in to_evict {
                        let item = (pos * shards) + shard_idx;
                        ret.push(item);
                    }
                }
            }
        }
        ret
    }
}

#[derive(Clone)]
struct Entry {
    ptr: *mut Node,
    size: u64,
}

impl Default for Entry {
    fn default() -> Self {
        Self { ptr: ptr::null_mut(), size: 0 }
    }
}

struct Shard {
    list: DoublyLinkedList,
    entries: Vec<Entry>,
    capacity: u64,
    size: u64,
}

impl Shard {
    fn new(capacity: u64) -> Self {
        assert!(capacity > 0, "shard capacity must be non-zero");

        Self {
            list: DoublyLinkedList::default(),
            entries: vec![],
            capacity,
            size: 0,
        }
    }

    /// `PageId`s in the shard list are indexes of the entries.
    fn accessed(&mut self, pos: usize, size: u64) -> Vec<PageId> {
        if pos >= self.entries.len() {
            self.entries.resize(pos + 1, Entry::default());
        }

        {
            let entry = &mut self.entries[pos];

            self.size -= entry.size;
            entry.size = size;
            self.size += size;

            if entry.ptr.is_null() {
                entry.ptr = self.list.push_head(PageId::try_from(pos).unwrap());
            } else {
                entry.ptr = self.list.promote(entry.ptr);
            }
        }

        let mut to_evict = vec![];
        while self.size > self.capacity {
            if self.list.len() == 1 {
                // don't evict what we just added
                break;
            }

            let min_pid = self.list.pop_tail().unwrap();
            let min_pid_idx = safe_usize(min_pid);

            self.entries[min_pid_idx].ptr = ptr::null_mut();

            to_evict.push(min_pid);

            self.size -= self.entries[min_pid_idx].size;
            self.entries[min_pid_idx].size = 0;
        }

        to_evict
    }
}

#[inline]
fn safe_usize(value: PageId) -> usize {
    usize::try_from(value).unwrap()
}

#[test]
fn lru_smoke_test() {
    use crate::pin;

    let lru = Lru::new(256);
    for i in 0..1000 {
        let guard = pin();
        lru.accessed(i, 16, &guard);
    }
}
<|endoftext|>


<commit_before>extern crate para_bm;

use std::time::Duration;

use para_bm::{sleep_ns};

fn main () {

    // first "throw away" run
    let mut d = Duration::span(|| {
        sleep_ns(1);
    });
    let ns = d.num_nanoseconds().unwrap();
    println!("num nano seconds first run {}", ns);

    // iterate to get more cache hits, etc...
    for _ in 0 .. 10 {
        d = Duration::span(|| {
            sleep_ns(1);
        });
        let ns = d.num_nanoseconds().unwrap();
        println!("num nano seconds {}", ns);
    }

}
<commit_msg>pass function to a my_bench function<commit_after>extern crate para_bm;

use std::time::Duration;

use para_bm::{sleep_ns};

fn fast () {
    sleep_ns(1000);
}

fn slow () {
    sleep_ns(1000000);
}

fn my_bench<F> (f: F) where F: Fn() {

    // first "throw away" run
    let mut d = Duration::span(|| {
        f();
    });
    let ns = d.num_nanoseconds().unwrap();
    println!("num nano seconds first run {}", ns);

    // iterate to get more cache hits, etc...
    for _ in 0 .. 10 {
        d = Duration::span(|| {
            f();
        });
        let ns = d.num_nanoseconds().unwrap();
        println!("num nano seconds {}", ns);
    }
}

fn main () {

    my_bench(||{
        slow()
    });

    my_bench(||{
        fast()
    });

}
<|endoftext|>


<commit_before>//!
//! The **nodrop** crate has the following cargo feature flags:
//!
//! - `std`
//!   - Optional, enabled by default
//!   - Requires Rust 1.6 *to disable*
//!   - Use libstd
//! - `use_needs_drop`
//!   - Optional
//!   - Requires nightly channel.
//!   - Use `needs_drop` to skip overwriting if not necessary
//! - `use_union`
//!   - Optional
//!   - Requires nightly channel
//!   - Using untagged union, finally we have an implementation of `NoDrop` without hacks,
//!     for example the fact that `NoDrop<T>` never has a destructor anymore.
//!

#![cfg_attr(feature="use_needs_drop", feature(core_intrinsics))]

#![cfg_attr(not(any(test, feature="std")), no_std)]
#[cfg(not(any(test, feature="std")))]
extern crate core as std;

#[cfg(not(feature = "use_union"))]
extern crate odds;

#[cfg(feature = "use_union")]
extern crate nodrop_union as imp;

pub use imp::NoDrop;

#[cfg(not(feature = "use_union"))]
mod imp {
    use odds::debug_assert_unreachable;
    use std::ptr;
    use std::mem;
    use std::ops::{Deref, DerefMut};

    /// repr(u8) - Make sure the non-nullable pointer optimization does not occur!
    #[repr(u8)]
    enum Flag<T> {
        Alive(T),
        Dropped,
    }

    /// A type holding **T** that will not call its destructor on drop
    pub struct NoDrop<T>(Flag<T>);

    impl<T> NoDrop<T> {
        /// Create a new **NoDrop**.
        #[inline]
        pub fn new(value: T) -> NoDrop<T> {
            NoDrop(Flag::Alive(value))
        }

        /// Extract the inner value.
        ///
        /// Once extracted, the value can of course drop again.
        #[inline]
        pub fn into_inner(mut self) -> T {
            let inner = unsafe {
                ptr::read(&mut *self)
            };
            // skip Drop, so we don't even have to overwrite
            mem::forget(self);
            inner
        }
    }

    #[cfg(not(feature = "use_needs_drop"))]
    #[inline]
    fn needs_drop<T>() -> bool {
        true
    }

    #[cfg(feature = "use_needs_drop")]
    #[inline]
    fn needs_drop<T>() -> bool {
        unsafe {
            ::std::intrinsics::needs_drop::<T>()
        }
    }

    impl<T> Drop for NoDrop<T> {
        fn drop(&mut self) {
            if needs_drop::<T>() {
                // inhibit drop
                unsafe {
                    ptr::write(&mut self.0, Flag::Dropped);
                }
            }
        }
    }

    impl<T> Deref for NoDrop<T> {
        type Target = T;

        // Use type invariant, always Flag::Alive.
        #[inline]
        fn deref(&self) -> &T {
            match self.0 {
                Flag::Alive(ref inner) => inner,
                _ => unsafe { debug_assert_unreachable() }
            }
        }
    }

    impl<T> DerefMut for NoDrop<T> {
        // Use type invariant, always Flag::Alive.
        #[inline]
        fn deref_mut(&mut self) -> &mut T {
            match self.0 {
                Flag::Alive(ref mut inner) => inner,
                _ => unsafe { debug_assert_unreachable() }
            }
        }
    }

    #[cfg(test)]
    #[test]
    fn test_no_nonnullable_opt() {
        // Make sure `Flag` does not apply the non-nullable pointer optimization
        // as Option would do.
        assert!(mem::size_of::<Flag<&i32>>() > mem::size_of::<&i32>());
        assert!(mem::size_of::<Flag<Vec<i32>>>() > mem::size_of::<Vec<i32>>());
        assert!(mem::size_of::<Option<Flag<&i32>>>() > mem::size_of::<Flag<&i32>>());
    }
}

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

    #[test]
    fn test_drop() {
        use std::cell::Cell;

        let flag = &Cell::new(0);

        struct Bump<'a>(&'a Cell<i32>);

        impl<'a> Drop for Bump<'a> {
            fn drop(&mut self) {
                let n = self.0.get();
                self.0.set(n + 1);
            }
        }

        {
            let _ = NoDrop::new([Bump(flag), Bump(flag)]);
        }
        assert_eq!(flag.get(), 0);

        // test something with the nullable pointer optimization
        flag.set(0);

        {
            let mut array = NoDrop::new(Vec::new());
            array.push(vec![Bump(flag)]);
            array.push(vec![Bump(flag), Bump(flag)]);
            array.push(vec![]);
            array.push(vec![Bump(flag)]);
            drop(array.pop());
            assert_eq!(flag.get(), 1);
            drop(array.pop());
            assert_eq!(flag.get(), 1);
            drop(array.pop());
            assert_eq!(flag.get(), 3);
        }

        // last one didn't drop.
        assert_eq!(flag.get(), 3);

        flag.set(0);
        {
            let array = NoDrop::new(Bump(flag));
            array.into_inner();
            assert_eq!(flag.get(), 1);
        }
        assert_eq!(flag.get(), 1);
    }
}
<commit_msg>Use u8 field in the NoDrop Dropped variant<commit_after>//!
//! The **nodrop** crate has the following cargo feature flags:
//!
//! - `std`
//!   - Optional, enabled by default
//!   - Requires Rust 1.6 *to disable*
//!   - Use libstd
//! - `use_needs_drop`
//!   - Optional
//!   - Requires nightly channel.
//!   - Use `needs_drop` to skip overwriting if not necessary
//! - `use_union`
//!   - Optional
//!   - Requires nightly channel
//!   - Using untagged union, finally we have an implementation of `NoDrop` without hacks,
//!     for example the fact that `NoDrop<T>` never has a destructor anymore.
//!

#![cfg_attr(feature="use_needs_drop", feature(core_intrinsics))]

#![cfg_attr(not(any(test, feature="std")), no_std)]
#[cfg(not(any(test, feature="std")))]
extern crate core as std;

#[cfg(not(feature = "use_union"))]
extern crate odds;

#[cfg(feature = "use_union")]
extern crate nodrop_union as imp;

pub use imp::NoDrop;

#[cfg(not(feature = "use_union"))]
mod imp {
    use odds::debug_assert_unreachable;
    use std::ptr;
    use std::mem;
    use std::ops::{Deref, DerefMut};

    /// repr(u8) - Make sure the non-nullable pointer optimization does not occur!
    #[repr(u8)]
    enum Flag<T> {
        Alive(T),
        // Dummy u8 field below, again to beat the enum layout opt
        Dropped(u8),
    }

    /// A type holding **T** that will not call its destructor on drop
    pub struct NoDrop<T>(Flag<T>);

    impl<T> NoDrop<T> {
        /// Create a new **NoDrop**.
        #[inline]
        pub fn new(value: T) -> NoDrop<T> {
            NoDrop(Flag::Alive(value))
        }

        /// Extract the inner value.
        ///
        /// Once extracted, the value can of course drop again.
        #[inline]
        pub fn into_inner(mut self) -> T {
            let inner = unsafe {
                ptr::read(&mut *self)
            };
            // skip Drop, so we don't even have to overwrite
            mem::forget(self);
            inner
        }
    }

    #[cfg(not(feature = "use_needs_drop"))]
    #[inline]
    fn needs_drop<T>() -> bool {
        true
    }

    #[cfg(feature = "use_needs_drop")]
    #[inline]
    fn needs_drop<T>() -> bool {
        unsafe {
            ::std::intrinsics::needs_drop::<T>()
        }
    }

    impl<T> Drop for NoDrop<T> {
        fn drop(&mut self) {
            if needs_drop::<T>() {
                // inhibit drop
                unsafe {
                    ptr::write(&mut self.0, Flag::Dropped(0));
                }
            }
        }
    }

    impl<T> Deref for NoDrop<T> {
        type Target = T;

        // Use type invariant, always Flag::Alive.
        #[inline]
        fn deref(&self) -> &T {
            match self.0 {
                Flag::Alive(ref inner) => inner,
                _ => unsafe { debug_assert_unreachable() }
            }
        }
    }

    impl<T> DerefMut for NoDrop<T> {
        // Use type invariant, always Flag::Alive.
        #[inline]
        fn deref_mut(&mut self) -> &mut T {
            match self.0 {
                Flag::Alive(ref mut inner) => inner,
                _ => unsafe { debug_assert_unreachable() }
            }
        }
    }

    #[cfg(test)]
    #[test]
    fn test_no_nonnullable_opt() {
        // Make sure `Flag` does not apply the non-nullable pointer optimization
        // as Option would do.
        assert!(mem::size_of::<Flag<&i32>>() > mem::size_of::<&i32>());
        assert!(mem::size_of::<Flag<Vec<i32>>>() > mem::size_of::<Vec<i32>>());
        assert!(mem::size_of::<Option<Flag<&i32>>>() > mem::size_of::<Flag<&i32>>());
    }
}

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

    #[test]
    fn test_drop() {
        use std::cell::Cell;

        let flag = &Cell::new(0);

        struct Bump<'a>(&'a Cell<i32>);

        impl<'a> Drop for Bump<'a> {
            fn drop(&mut self) {
                let n = self.0.get();
                self.0.set(n + 1);
            }
        }

        {
            let _ = NoDrop::new([Bump(flag), Bump(flag)]);
        }
        assert_eq!(flag.get(), 0);

        // test something with the nullable pointer optimization
        flag.set(0);

        {
            let mut array = NoDrop::new(Vec::new());
            array.push(vec![Bump(flag)]);
            array.push(vec![Bump(flag), Bump(flag)]);
            array.push(vec![]);
            array.push(vec![Bump(flag)]);
            drop(array.pop());
            assert_eq!(flag.get(), 1);
            drop(array.pop());
            assert_eq!(flag.get(), 1);
            drop(array.pop());
            assert_eq!(flag.get(), 3);
        }

        // last one didn't drop.
        assert_eq!(flag.get(), 3);

        flag.set(0);
        {
            let array = NoDrop::new(Bump(flag));
            array.into_inner();
            assert_eq!(flag.get(), 1);
        }
        assert_eq!(flag.get(), 1);
    }
}
<|endoftext|>


<commit_before>extern crate num;
use std::collections::BTreeSet;
use std::cmp;
use rand::Rng;
use std::ops::Range;
use std::iter::Rev;
use super::{Genetic, SISO};
use std::marker::PhantomData;

///Defines an opcode for the Mep. Every opcode contains an instruction and two parameter indices. These specify which
///previous opcodes produced the result required as inputs to this opcode. These parameters can also come from the inputs
///to the program, which sequentially preceed the internal instructions.
#[derive(Clone, Copy)]
struct Opcode<Ins> {
    instruction: Ins,
    first: usize,
    second: usize,
}

///A multi-expression program represented using a series of operations that can reuse results of previous operations.
pub struct Mep<Ins, R, Param, F1, F2> {
    program: Vec<Opcode<Ins>>,
    pub unit_mutate_size: usize,
    pub crossover_points: usize,
    inputs: usize,
    outputs: usize,
    mutator: F1,
    processor: F2,
    _phantom: (PhantomData<R>, PhantomData<Param>),
}

impl<Ins, R, Param, F1, F2> Clone for Mep<Ins, R, Param, F1, F2>
    where Ins: Clone, F1: Copy, F2: Copy
{
    fn clone(&self) -> Self {
        Mep{
            program: self.program.clone(),
            unit_mutate_size: self.unit_mutate_size,
            crossover_points: self.crossover_points,
            inputs: self.inputs,
            outputs: self.outputs,
            mutator: self.mutator,
            processor: self.processor,
            _phantom: (PhantomData, PhantomData),
        }
    }
}

impl<Ins, R, Param, F1, F2> Mep<Ins, R, Param, F1, F2> {
    ///Generates a new Mep with a particular size and takes a closure to generate random instructions.
    ///Takes an RNG as well to generate random internal data for each instruction. This Rng is different from the Mep's
    ///Rng, thus it is parameterized separately here.
    pub fn new<I, Rg>(inputs: usize, outputs: usize, unit_mutate_size: usize, crossover_points: usize, rng: &mut Rg,
        instruction_iter: I, mutator: F1, processor: F2) -> Self
        where I: Iterator<Item=Ins>, Rg: Rng, F1: Fn(&mut Ins, &mut R), F2: Fn(&Ins, Param, Param) -> Param
    {
        Mep{
            program: instruction_iter.enumerate()
                .map(|(index, ins)| Opcode{
                        instruction: ins,
                        first: rng.gen_range(0, index + inputs),
                        second: rng.gen_range(0, index + inputs),
                    }
                ).collect(),
            unit_mutate_size: unit_mutate_size,
            crossover_points: crossover_points,
            inputs: inputs,
            outputs: outputs,
            mutator: mutator,
            processor: processor,
            _phantom: (PhantomData, PhantomData),
        }
    }
}

impl<Ins, R, Param, F1, F2> Genetic<R> for Mep<Ins, R, Param, F1, F2>
    where R: Rng, Ins: Clone, Param: Clone, F1: Copy + Fn(&mut Ins, &mut R), F2: Copy
{
    fn mate(parents: (&Self, &Self), rng: &mut R) -> Self {
        //Each Mep must have the same amount of inputs
        //TODO: Once Rust implements generic values, this can be made explicit and is not needed
        assert!(parents.0.inputs == parents.1.inputs);
        assert!(parents.0.outputs == parents.1.outputs);
        //Get the smallest of the two lengths
        let total_instructions = cmp::min(parents.0.program.len(), parents.1.program.len());
        let crossover_choice = rng.gen_range(0, 2);
        Mep{program:
            //Generate a randomly sized sequence between 1 and crossover_points
            (0..rng.gen_range(1, cmp::min(total_instructions / 2, {
                if crossover_choice == 0 {parents.0}
                else {parents.1}}.crossover_points)))
            //Map these to random crossover points
            .map(|_| rng.gen_range(0, total_instructions))
            //Add total_instructions at the end so we can generate a range with it
            .chain(Some(total_instructions))
            //Sort them by value into BTree, which removes duplicates and orders them
            .fold(BTreeSet::new(), |mut set, i| {set.insert(i); set})
            //Iterate over the sorted values
            .iter()
            //Turn every copy of two, prepending a 0, into a range
            .scan(0, |prev, x| {let out = Some(*prev..*x); *prev = *x; out})
            //Enumerate by index to differentiate odd and even values
            .enumerate()
            //Map even pairs to ranges in parent 0 and odd ones to ranges in parent 1 and expand the ranges
            .flat_map(|(index, range)| {
                {if index % 2 == 0 {parents.0} else {parents.1}}.program[range].iter().cloned()
            })
            //Collect all the instruction ranges from each parent
            .collect(),

            unit_mutate_size: if parents.0.unit_mutate_size < parents.1.unit_mutate_size {
                rng.gen_range(parents.0.unit_mutate_size, parents.1.unit_mutate_size + 1)
            } else {
                rng.gen_range(parents.1.unit_mutate_size, parents.0.unit_mutate_size + 1)
            },

            crossover_points: if parents.0.crossover_points < parents.1.crossover_points {
                rng.gen_range(parents.0.crossover_points, parents.1.crossover_points + 1)
            } else {
                rng.gen_range(parents.1.crossover_points, parents.0.crossover_points + 1)
            },

            inputs: parents.0.inputs,
            outputs: parents.0.outputs,
            mutator: {if rng.gen_range(0, 2) == 0 {parents.0} else {parents.1}}.mutator,
            processor: {if rng.gen_range(0, 2) == 0 {parents.0} else {parents.1}}.processor,
            _phantom: (PhantomData, PhantomData),
        }
    }

    ///The Mep mutate function operates using the unit_mutate_size. This variable specifies the amount of instructions
    ///for which a single mutation is expect to occour every time mutate is called. This variable can be mutated inside
    ///of mutate, in which case it may never go below 1, but may tend towards infinity in increments of 1. This variable
    ///is implemented as a u64 to permit it to expand unbounded to mutation levels that are so low that mutations
    ///virtually never happen. Allowing this to mutate allows species to find the equilibrium between genomic
    ///adaptability and stability. If a species develops information gathering, then it can adapt intellegently, making
    ///it possibly more beneficial to operate at lower mutation rates. Setting the default mutation rate for species
    ///properly, or allowing it to adapt as the simulation continues, permits species to survive more frequently that
    ///are randomly generated.
    fn mutate(&mut self, rng: &mut R) {
        //Mutate unit_mutate_size
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            //Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.unit_mutate_size += 1,
                1 => if self.unit_mutate_size > 1 {self.unit_mutate_size -= 1},
                _ => unreachable!(),
            }
        }
        //Mutate crossover_points
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            //Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.crossover_points += 1,
                1 => if self.crossover_points > 1 {self.crossover_points -= 1},
                _ => unreachable!(),
            }
        }

        //Mutate the instructions using the mutator
        loop {
            //Choose a random location in the instructions and then add a random value up to the unit_mutate_size
            let choice = rng.gen_range(0, self.program.len()) + rng.gen_range(0, self.unit_mutate_size);
            //Whenever we choose a location outside the vector reject the choice and end mutation
            if choice >= self.program.len() {
                break;
            }
            let op = &mut self.program[choice];
            //Randomly mutate only one of the things contained here
            match rng.gen_range(0, 3) {
                0 => (self.mutator)(&mut op.instruction, rng),
                1 => op.first = rng.gen_range(0, choice + self.inputs),
                2 => op.second = rng.gen_range(0, choice + self.inputs),
                _ => unreachable!(),
            }
        }
    }
}

impl<'a, Ins: 'a, R: 'a, Param: 'a, F1: 'a, F2: 'a> SISO<'a, Param, Param> for Mep<Ins, R, Param, F1, F2>
    where F2: Fn(&Ins, Param, Param) -> Param, Param: Clone
{
    type Iter = ResultIterator<'a, Ins, R, Param, F1, F2>;

    fn compute(&'a self, inputs: &'a [Param]) -> Self::Iter {
        //Ensure we have enough opcodes to produce the desired amount of outputs, otherwise the programmer has failed
        assert!(self.outputs <= self.program.len());
        ResultIterator{
            mep: self,
            buff: vec![None; self.program.len()],
            solve_iter: ((self.program.len() + self.inputs - self.outputs)..(self.program.len() + self.inputs)).rev(),
            inputs: inputs,
        }
    }
}

pub struct ResultIterator<'a, Ins: 'a, R: 'a, Param: 'a, F1: 'a, F2: 'a> {
    mep: &'a Mep<Ins, R, Param, F1, F2>,
    buff: Vec<Option<Param>>,
    solve_iter: Rev<Range<usize>>,
    inputs: &'a [Param],
}

impl<'a, Ins, R, Param, F1, F2> ResultIterator<'a, Ins, R, Param, F1, F2>
    where F2: Fn(&Ins, Param, Param) -> Param, Param: Clone
{
    fn op_solved(&mut self, i: usize) -> Param {
        //If this is an input, it is already solved, so return the result immediately
        if i < self.mep.inputs {
            return unsafe{
                self.inputs.get_unchecked(i)
            }.clone();
        }
        //Check if this has been evaluated or not
        let possible = unsafe{
            self.buff.get_unchecked(i - self.mep.inputs)
        }.clone();
        match possible {
            //If it has, return the value
            Some(x) => x,
            //If it hasnt been solved
            None => {
                //Get a reference to the opcode
                let op = unsafe{
                    self.mep.program.get_unchecked(i - self.mep.inputs)
                };
                //Compute the result of the operation, ensuring the inputs are solved beforehand
                let result = (self.mep.processor)(&op.instruction, self.op_solved(op.first), self.op_solved(op.second));
                //Properly store the Some result to the buffer
                unsafe{
                    *self.buff.get_unchecked_mut(i - self.mep.inputs) = Some(result.clone())
                };
                //Return the result
                result
            }
        }
    }
}

impl<'a, Ins, R, Param, F1, F2> Iterator for ResultIterator<'a, Ins, R, Param, F1, F2>
    where F2: Fn(&Ins, Param, Param) -> Param, Param: Clone
{
    type Item = Param;
    fn next(&mut self) -> Option<Param> {
        match self.solve_iter.next() {
            None => None,
            Some(i) => Some(self.op_solved(i)),
        }
    }
}

#[cfg(test)]
mod tests {
    use rand::{Isaac64Rng, SeedableRng, Rng};
    use super::*;
    use super::super::{Genetic, SISO};

    fn mutator(_: &mut i32, _: &mut Isaac64Rng) {}
    fn processor(_: &i32, _: i32, _: i32) -> i32 {0}

    #[test]
    fn new() {
        let a = Mep::new(3, 1, 10, 10, &mut Isaac64Rng::from_seed(&[1, 2, 3, 4]), 0..30, mutator, processor);

        assert_eq!(a.program.iter().map(|i| i.instruction).collect::<Vec<_>>(), (0..30).collect::<Vec<_>>());
    }

    #[test]
    fn crossover() {
        let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
        let (a, b) = {
            let mut clos = || Mep::new(3, 1, 10, 10, &mut rng, 0..30, mutator, processor);
            (clos(), clos())
        };
        let old_rngs: Vec<_> = rng.clone().gen_iter::<i32>().take(5).collect();
        let _ = Mep::mate((&a, &b), &mut rng);
        //Ensure that rng was borrowed mutably
        assert!(rng.clone().gen_iter::<i32>().take(5).collect::<Vec<_>>() != old_rngs);
    }

    #[test]
    fn compute() {
        let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
        let a = Mep::new(3, 1, 10, 10, &mut rng, 0..30, mutator, processor);

        let inputs = [2, 3, 4];
        assert_eq!(a.compute(&inputs[..]).collect::<Vec<_>>(), [0]);
    }
}
<commit_msg>fix bug with crossover 1<commit_after>extern crate num;
use std::collections::BTreeSet;
use std::cmp;
use rand::Rng;
use std::ops::Range;
use std::iter::Rev;
use super::{Genetic, SISO};
use std::marker::PhantomData;

///Defines an opcode for the Mep. Every opcode contains an instruction and two parameter indices. These specify which
///previous opcodes produced the result required as inputs to this opcode. These parameters can also come from the inputs
///to the program, which sequentially preceed the internal instructions.
#[derive(Clone, Copy)]
struct Opcode<Ins> {
    instruction: Ins,
    first: usize,
    second: usize,
}

///A multi-expression program represented using a series of operations that can reuse results of previous operations.
pub struct Mep<Ins, R, Param, F1, F2> {
    program: Vec<Opcode<Ins>>,
    pub unit_mutate_size: usize,
    pub crossover_points: usize,
    inputs: usize,
    outputs: usize,
    mutator: F1,
    processor: F2,
    _phantom: (PhantomData<R>, PhantomData<Param>),
}

impl<Ins, R, Param, F1, F2> Clone for Mep<Ins, R, Param, F1, F2>
    where Ins: Clone, F1: Copy, F2: Copy
{
    fn clone(&self) -> Self {
        Mep{
            program: self.program.clone(),
            unit_mutate_size: self.unit_mutate_size,
            crossover_points: self.crossover_points,
            inputs: self.inputs,
            outputs: self.outputs,
            mutator: self.mutator,
            processor: self.processor,
            _phantom: (PhantomData, PhantomData),
        }
    }
}

impl<Ins, R, Param, F1, F2> Mep<Ins, R, Param, F1, F2> {
    ///Generates a new Mep with a particular size and takes a closure to generate random instructions.
    ///Takes an RNG as well to generate random internal data for each instruction. This Rng is different from the Mep's
    ///Rng, thus it is parameterized separately here.
    pub fn new<I, Rg>(inputs: usize, outputs: usize, unit_mutate_size: usize, crossover_points: usize, rng: &mut Rg,
        instruction_iter: I, mutator: F1, processor: F2) -> Self
        where I: Iterator<Item=Ins>, Rg: Rng, F1: Fn(&mut Ins, &mut R), F2: Fn(&Ins, Param, Param) -> Param
    {
        Mep{
            program: instruction_iter.enumerate()
                .map(|(index, ins)| Opcode{
                        instruction: ins,
                        first: rng.gen_range(0, index + inputs),
                        second: rng.gen_range(0, index + inputs),
                    }
                ).collect(),
            unit_mutate_size: unit_mutate_size,
            crossover_points: crossover_points,
            inputs: inputs,
            outputs: outputs,
            mutator: mutator,
            processor: processor,
            _phantom: (PhantomData, PhantomData),
        }
    }
}

impl<Ins, R, Param, F1, F2> Genetic<R> for Mep<Ins, R, Param, F1, F2>
    where R: Rng, Ins: Clone, Param: Clone, F1: Copy + Fn(&mut Ins, &mut R), F2: Copy
{
    fn mate(parents: (&Self, &Self), rng: &mut R) -> Self {
        //Each Mep must have the same amount of inputs
        //TODO: Once Rust implements generic values, this can be made explicit and is not needed
        assert!(parents.0.inputs == parents.1.inputs);
        assert!(parents.0.outputs == parents.1.outputs);
        //Get the smallest of the two lengths
        let total_instructions = cmp::min(parents.0.program.len(), parents.1.program.len());
        let crossover_choice = rng.gen_range(0, 2);
        Mep{program:
            //Generate a randomly sized sequence between 1 and crossover_points
            (0..rng.gen_range(1, cmp::min(total_instructions / 2, {
                if crossover_choice == 0 {parents.0}
                else {parents.1}}.crossover_points + 1)))
            //Map these to random crossover points
            .map(|_| rng.gen_range(0, total_instructions))
            //Add total_instructions at the end so we can generate a range with it
            .chain(Some(total_instructions))
            //Sort them by value into BTree, which removes duplicates and orders them
            .fold(BTreeSet::new(), |mut set, i| {set.insert(i); set})
            //Iterate over the sorted values
            .iter()
            //Turn every copy of two, prepending a 0, into a range
            .scan(0, |prev, x| {let out = Some(*prev..*x); *prev = *x; out})
            //Enumerate by index to differentiate odd and even values
            .enumerate()
            //Map even pairs to ranges in parent 0 and odd ones to ranges in parent 1 and expand the ranges
            .flat_map(|(index, range)| {
                {if index % 2 == 0 {parents.0} else {parents.1}}.program[range].iter().cloned()
            })
            //Collect all the instruction ranges from each parent
            .collect(),

            unit_mutate_size: if parents.0.unit_mutate_size < parents.1.unit_mutate_size {
                rng.gen_range(parents.0.unit_mutate_size, parents.1.unit_mutate_size + 1)
            } else {
                rng.gen_range(parents.1.unit_mutate_size, parents.0.unit_mutate_size + 1)
            },

            crossover_points: if parents.0.crossover_points < parents.1.crossover_points {
                rng.gen_range(parents.0.crossover_points, parents.1.crossover_points + 1)
            } else {
                rng.gen_range(parents.1.crossover_points, parents.0.crossover_points + 1)
            },

            inputs: parents.0.inputs,
            outputs: parents.0.outputs,
            mutator: {if rng.gen_range(0, 2) == 0 {parents.0} else {parents.1}}.mutator,
            processor: {if rng.gen_range(0, 2) == 0 {parents.0} else {parents.1}}.processor,
            _phantom: (PhantomData, PhantomData),
        }
    }

    ///The Mep mutate function operates using the unit_mutate_size. This variable specifies the amount of instructions
    ///for which a single mutation is expect to occour every time mutate is called. This variable can be mutated inside
    ///of mutate, in which case it may never go below 1, but may tend towards infinity in increments of 1. This variable
    ///is implemented as a u64 to permit it to expand unbounded to mutation levels that are so low that mutations
    ///virtually never happen. Allowing this to mutate allows species to find the equilibrium between genomic
    ///adaptability and stability. If a species develops information gathering, then it can adapt intellegently, making
    ///it possibly more beneficial to operate at lower mutation rates. Setting the default mutation rate for species
    ///properly, or allowing it to adapt as the simulation continues, permits species to survive more frequently that
    ///are randomly generated.
    fn mutate(&mut self, rng: &mut R) {
        //Mutate unit_mutate_size
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            //Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.unit_mutate_size += 1,
                1 => if self.unit_mutate_size > 1 {self.unit_mutate_size -= 1},
                _ => unreachable!(),
            }
        }
        //Mutate crossover_points
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            //Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.crossover_points += 1,
                1 => if self.crossover_points > 1 {self.crossover_points -= 1},
                _ => unreachable!(),
            }
        }

        //Mutate the instructions using the mutator
        loop {
            //Choose a random location in the instructions and then add a random value up to the unit_mutate_size
            let choice = rng.gen_range(0, self.program.len()) + rng.gen_range(0, self.unit_mutate_size);
            //Whenever we choose a location outside the vector reject the choice and end mutation
            if choice >= self.program.len() {
                break;
            }
            let op = &mut self.program[choice];
            //Randomly mutate only one of the things contained here
            match rng.gen_range(0, 3) {
                0 => (self.mutator)(&mut op.instruction, rng),
                1 => op.first = rng.gen_range(0, choice + self.inputs),
                2 => op.second = rng.gen_range(0, choice + self.inputs),
                _ => unreachable!(),
            }
        }
    }
}

impl<'a, Ins: 'a, R: 'a, Param: 'a, F1: 'a, F2: 'a> SISO<'a, Param, Param> for Mep<Ins, R, Param, F1, F2>
    where F2: Fn(&Ins, Param, Param) -> Param, Param: Clone
{
    type Iter = ResultIterator<'a, Ins, R, Param, F1, F2>;

    fn compute(&'a self, inputs: &'a [Param]) -> Self::Iter {
        //Ensure we have enough opcodes to produce the desired amount of outputs, otherwise the programmer has failed
        assert!(self.outputs <= self.program.len());
        ResultIterator{
            mep: self,
            buff: vec![None; self.program.len()],
            solve_iter: ((self.program.len() + self.inputs - self.outputs)..(self.program.len() + self.inputs)).rev(),
            inputs: inputs,
        }
    }
}

pub struct ResultIterator<'a, Ins: 'a, R: 'a, Param: 'a, F1: 'a, F2: 'a> {
    mep: &'a Mep<Ins, R, Param, F1, F2>,
    buff: Vec<Option<Param>>,
    solve_iter: Rev<Range<usize>>,
    inputs: &'a [Param],
}

impl<'a, Ins, R, Param, F1, F2> ResultIterator<'a, Ins, R, Param, F1, F2>
    where F2: Fn(&Ins, Param, Param) -> Param, Param: Clone
{
    fn op_solved(&mut self, i: usize) -> Param {
        //If this is an input, it is already solved, so return the result immediately
        if i < self.mep.inputs {
            return unsafe{
                self.inputs.get_unchecked(i)
            }.clone();
        }
        //Check if this has been evaluated or not
        let possible = unsafe{
            self.buff.get_unchecked(i - self.mep.inputs)
        }.clone();
        match possible {
            //If it has, return the value
            Some(x) => x,
            //If it hasnt been solved
            None => {
                //Get a reference to the opcode
                let op = unsafe{
                    self.mep.program.get_unchecked(i - self.mep.inputs)
                };
                //Compute the result of the operation, ensuring the inputs are solved beforehand
                let result = (self.mep.processor)(&op.instruction, self.op_solved(op.first), self.op_solved(op.second));
                //Properly store the Some result to the buffer
                unsafe{
                    *self.buff.get_unchecked_mut(i - self.mep.inputs) = Some(result.clone())
                };
                //Return the result
                result
            }
        }
    }
}

impl<'a, Ins, R, Param, F1, F2> Iterator for ResultIterator<'a, Ins, R, Param, F1, F2>
    where F2: Fn(&Ins, Param, Param) -> Param, Param: Clone
{
    type Item = Param;
    fn next(&mut self) -> Option<Param> {
        match self.solve_iter.next() {
            None => None,
            Some(i) => Some(self.op_solved(i)),
        }
    }
}

#[cfg(test)]
mod tests {
    use rand::{Isaac64Rng, SeedableRng, Rng};
    use super::*;
    use super::super::{Genetic, SISO};

    fn mutator(_: &mut i32, _: &mut Isaac64Rng) {}
    fn processor(_: &i32, _: i32, _: i32) -> i32 {0}

    #[test]
    fn new() {
        let a = Mep::new(3, 1, 10, 10, &mut Isaac64Rng::from_seed(&[1, 2, 3, 4]), 0..30, mutator, processor);

        assert_eq!(a.program.iter().map(|i| i.instruction).collect::<Vec<_>>(), (0..30).collect::<Vec<_>>());
    }

    #[test]
    fn crossover() {
        let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
        let (a, b) = {
            let mut clos = || Mep::new(3, 1, 10, 10, &mut rng, 0..30, mutator, processor);
            (clos(), clos())
        };
        let old_rngs: Vec<_> = rng.clone().gen_iter::<i32>().take(5).collect();
        let _ = Mep::mate((&a, &b), &mut rng);
        //Ensure that rng was borrowed mutably
        assert!(rng.clone().gen_iter::<i32>().take(5).collect::<Vec<_>>() != old_rngs);
    }

    #[test]
    fn compute() {
        let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
        let a = Mep::new(3, 1, 10, 10, &mut rng, 0..30, mutator, processor);

        let inputs = [2, 3, 4];
        assert_eq!(a.compute(&inputs[..]).collect::<Vec<_>>(), [0]);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A one-dimensional length, tagged with its units.

use num_traits;

// Euclid has its own Zero and One traits instead of of using the num_traits equivalents.
// Unfortunately, num_traits::Zero requires Add, which opens a bag of sad things:
//  - Most importantly, for Point2D to implement Zero it would need to implement Add<Self> which we
//    don't want (we allow "Point + Vector" and "Vector + Vector" semantics and purposefully disallow
//    "Point + Point".
//  - Some operations that require, say, One and Div (for example Scale::inv) currently return a
//    type parameterized over T::Output which is ambiguous with num_traits::One because it inherits
//    Mul which also has an Output associated type. To fix it need to complicate type signatures
//    by using <T as Trait>::Output which makes the code and documentation harder to read.
//
// On the other hand, euclid::num::Zero/One are automatically implemented for all types that
// implement their num_traits counterpart. Euclid users never need to explicitly use
// euclid::num::Zero/One and can/should only manipulate the num_traits equivalents without risk
// of compatibility issues with euclid.

pub trait Zero {
    fn zero() -> Self;
}

impl<T: num_traits::Zero> Zero for T {
    fn zero() -> T {
        num_traits::Zero::zero()
    }
}

pub trait One {
    fn one() -> Self;
}

impl<T: num_traits::One> One for T {
    fn one() -> T {
        num_traits::One::one()
    }
}

/// Defines the nearest integer value to the original value.
pub trait Round: Copy {
    /// Rounds to the nearest integer value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn round(self) -> Self;
}
/// Defines the biggest integer equal or lower than the original value.
pub trait Floor: Copy {
    /// Rounds to the biggest integer equal or lower than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn floor(self) -> Self;
}
/// Defines the smallest integer equal or greater than the original value.
pub trait Ceil: Copy {
    /// Rounds to the smallest integer equal or greater than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn ceil(self) -> Self;
}

macro_rules! num_int {
    ($ty:ty) => {
        impl Round for $ty {
            #[inline]
            fn round(self) -> $ty {
                self
            }
        }
        impl Floor for $ty {
            #[inline]
            fn floor(self) -> $ty {
                self
            }
        }
        impl Ceil for $ty {
            #[inline]
            fn ceil(self) -> $ty {
                self
            }
        }
    };
}
macro_rules! num_float {
    ($ty:ty) => {
        impl Round for $ty {
            #[inline]
            fn round(self) -> $ty {
                num_traits::Float::round(self)
            }
        }
        impl Floor for $ty {
            #[inline]
            fn floor(self) -> $ty {
                num_traits::Float::floor(self)
            }
        }
        impl Ceil for $ty {
            #[inline]
            fn ceil(self) -> $ty {
                num_traits::Float::ceil(self)
            }
        }
    };
}

num_int!(i16);
num_int!(u16);
num_int!(i32);
num_int!(u32);
num_int!(i64);
num_int!(u64);
num_int!(isize);
num_int!(usize);
num_float!(f32);
num_float!(f64);
<commit_msg>Auto merge of #449 - jrmuizel:no-int, r=nical<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A one-dimensional length, tagged with its units.

use num_traits;

// Euclid has its own Zero and One traits instead of of using the num_traits equivalents.
// Unfortunately, num_traits::Zero requires Add, which opens a bag of sad things:
//  - Most importantly, for Point2D to implement Zero it would need to implement Add<Self> which we
//    don't want (we allow "Point + Vector" and "Vector + Vector" semantics and purposefully disallow
//    "Point + Point".
//  - Some operations that require, say, One and Div (for example Scale::inv) currently return a
//    type parameterized over T::Output which is ambiguous with num_traits::One because it inherits
//    Mul which also has an Output associated type. To fix it need to complicate type signatures
//    by using <T as Trait>::Output which makes the code and documentation harder to read.
//
// On the other hand, euclid::num::Zero/One are automatically implemented for all types that
// implement their num_traits counterpart. Euclid users never need to explicitly use
// euclid::num::Zero/One and can/should only manipulate the num_traits equivalents without risk
// of compatibility issues with euclid.

pub trait Zero {
    fn zero() -> Self;
}

impl<T: num_traits::Zero> Zero for T {
    fn zero() -> T {
        num_traits::Zero::zero()
    }
}

pub trait One {
    fn one() -> Self;
}

impl<T: num_traits::One> One for T {
    fn one() -> T {
        num_traits::One::one()
    }
}

/// Defines the nearest integer value to the original value.
pub trait Round: Copy {
    /// Rounds to the nearest integer value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn round(self) -> Self;
}
/// Defines the biggest integer equal or lower than the original value.
pub trait Floor: Copy {
    /// Rounds to the biggest integer equal or lower than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn floor(self) -> Self;
}
/// Defines the smallest integer equal or greater than the original value.
pub trait Ceil: Copy {
    /// Rounds to the smallest integer equal or greater than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn ceil(self) -> Self;
}

macro_rules! num_float {
    ($ty:ty) => {
        impl Round for $ty {
            #[inline]
            fn round(self) -> $ty {
                num_traits::Float::round(self)
            }
        }
        impl Floor for $ty {
            #[inline]
            fn floor(self) -> $ty {
                num_traits::Float::floor(self)
            }
        }
        impl Ceil for $ty {
            #[inline]
            fn ceil(self) -> $ty {
                num_traits::Float::ceil(self)
            }
        }
    };
}
num_float!(f32);
num_float!(f64);
<|endoftext|>


<commit_before>use super::component::log::StatusLog;
use super::{SeriesState, UIState, WatchState};
use crate::err::{self, Result};
use crate::util;
use anime::remote::ScoreParser;
use chrono::{Duration, Utc};
use smallvec::SmallVec;
use snafu::ResultExt;
use std::borrow::Cow;
use std::io;
use std::sync::mpsc;
use std::thread;
use termion::event::Key;
use termion::input::TermRead;
use termion::raw::{IntoRawMode, RawTerminal};
use tui::backend::{self, Backend};
use tui::layout::{Alignment, Constraint, Direction, Layout, Rect};
use tui::style::{Color, Modifier, Style};
use tui::terminal::{Frame, Terminal};
use tui::widgets::{Block, Borders, Paragraph, SelectableList, Text, Widget};

pub struct UI<'a, B>
where
    B: Backend,
{
    terminal: Terminal<B>,
    pub status_log: StatusLog<'a>,
}

macro_rules! create_stat_list {
    ($($header:expr => $value:expr),+) => {
        [$(
            create_stat_list!(h $header),
            create_stat_list!(v $header.len(), $value),
        )+]
    };

    (h $header:expr) => {
        Text::styled(format!("{}\n", $header), Style::default().modifier(Modifier::BOLD))
    };

    (v $len:expr, $value:expr) => {
        Text::styled(format!("{:^width$}\n\n", $value, width = $len), Style::default().modifier(Modifier::ITALIC))
    };
}

impl<'a, B> UI<'a, B>
where
    B: Backend,
{
    pub fn clear(&mut self) -> Result<()> {
        self.terminal.clear().context(err::IO)
    }

    pub fn draw<S>(&mut self, state: &UIState, score_parser: &S) -> Result<()>
    where
        S: ScoreParser + ?Sized,
    {
        let status_log = &mut self.status_log;

        self.terminal
            .draw(|mut frame| {
                // Top panels for series information
                let horiz_splitter = Layout::default()
                    .direction(Direction::Horizontal)
                    .constraints([Constraint::Min(20), Constraint::Percentage(70)].as_ref())
                    .split(frame.size());

                UI::draw_top_panels(state, &horiz_splitter, &mut frame);

                // Series info panel vertical splitter
                let info_panel_splitter = Layout::default()
                    .direction(Direction::Vertical)
                    .constraints([Constraint::Percentage(80), Constraint::Percentage(20)].as_ref())
                    .split(horiz_splitter[1]);

                UI::draw_info_panel(state, score_parser, &info_panel_splitter, &mut frame);
                UI::draw_status_bar(state, status_log, info_panel_splitter[1], &mut frame);
            })
            .context(err::IO)
    }

    fn draw_top_panels(state: &UIState, layout: &[Rect], frame: &mut Frame<B>) {
        let series_names = state
            .series
            .iter()
            .map(|series| &series.inner.nickname)
            .collect::<SmallVec<[_; 8]>>();

        let mut series_list = SelectableList::default()
            .block(Block::default().title("Series").borders(Borders::ALL))
            .items(&series_names)
            .select(Some(state.selected_series))
            .style(Style::default().fg(Color::White))
            .highlight_style(Style::default().fg(Color::Green).modifier(Modifier::ITALIC))
            .highlight_symbol(">");

        series_list.render(frame, layout[0]);
    }

    fn draw_info_panel<S>(state: &UIState, score_parser: &S, layout: &[Rect], frame: &mut Frame<B>)
    where
        S: ScoreParser + ?Sized,
    {
        Block::default()
            .title("Info")
            .borders(Borders::ALL)
            .render(frame, layout[0]);

        let info_layout = Layout::default()
            .direction(Direction::Vertical)
            .constraints(
                [
                    Constraint::Length(4),
                    Constraint::Percentage(70),
                    Constraint::Length(4),
                ]
                .as_ref(),
            )
            .margin(2)
            .split(layout[0]);

        if let Some(series) = state.cur_series() {
            UI::draw_series_info(series, score_parser, &info_layout, frame)
        }
    }

    fn draw_series_info<S>(
        series: &SeriesState,
        score_parser: &S,
        info_layout: &[Rect],
        frame: &mut Frame<B>,
    ) where
        S: ScoreParser + ?Sized,
    {
        let info = &series.inner.info;
        let entry = &series.inner.entry;

        // Series title
        {
            let text_items = {
                let mut items = SmallVec::<[_; 2]>::new();

                items.push(Text::styled(
                    &info.title.preferred,
                    Style::default().modifier(Modifier::BOLD),
                ));

                if entry.needs_sync() {
                    items.push(Text::styled(
                        " [*]",
                        Style::default().modifier(Modifier::ITALIC),
                    ));
                }

                items
            };

            Paragraph::new(text_items.iter())
                .alignment(Alignment::Center)
                .render(frame, info_layout[0]);
        }

        // Items in panel
        let stat_layout = Layout::default()
            .direction(Direction::Horizontal)
            .constraints(
                [
                    Constraint::Percentage(33),
                    Constraint::Percentage(33),
                    Constraint::Percentage(33),
                ]
                .as_ref(),
            )
            .split(info_layout[1]);

        {
            let left_items = create_stat_list!(
                "Watch Time" => {
                    let watch_time_mins = info.episodes * info.episode_length;
                    util::hm_from_mins(watch_time_mins as f32)
                },
                "Time Left" => {
                    let eps_left = info.episodes - entry.watched_eps().min(info.episodes);
                    let time_left_mins = eps_left * info.episode_length;

                    util::hm_from_mins(time_left_mins as f32)
                },
                "Episode Length" => format!("{}M", info.episode_length)
            );

            Paragraph::new(left_items.iter())
                .alignment(Alignment::Center)
                .render(frame, stat_layout[0]);
        }

        {
            let center_items = create_stat_list!(
                "Progress" => format!("{}|{}", entry.watched_eps(), info.episodes),
                "Score" => match entry.score() {
                    Some(score) => score_parser.score_to_str(score),
                    None => "??".into(),
                },
                "Status" => entry.status()
            );

            Paragraph::new(center_items.iter())
                .alignment(Alignment::Center)
                .render(frame, stat_layout[1]);
        }

        {
            let right_items = create_stat_list!(
                "Start Date" => match entry.start_date() {
                    Some(date) => format!("{}", date.format("%D")).into(),
                    None => Cow::Borrowed("??"),
                },
                "Finish Date" => match entry.end_date() {
                    Some(date) => format!("{}", date.format("%D")).into(),
                    None => Cow::Borrowed("??"),
                },
                "Rewatched" => entry.times_rewatched()
            );

            Paragraph::new(right_items.iter())
                .alignment(Alignment::Center)
                .render(frame, stat_layout[2]);
        }

        // Watch time needed indicator at bottom
        match series.watch_state {
            WatchState::Idle => (),
            WatchState::Watching(progress_time, _) => {
                let watch_time = progress_time - Utc::now();
                let watch_secs = watch_time.num_seconds();

                if watch_secs > 0 {
                    let remaining_mins = watch_secs as f32 / 60.0;

                    let text_str = format!(
                        "{} Remaining Until Progression",
                        util::ms_from_mins(remaining_mins)
                    );

                    let text = Text::styled(text_str, Style::default().modifier(Modifier::BOLD));

                    Paragraph::new([text].iter())
                        .alignment(Alignment::Center)
                        .render(frame, info_layout[2]);
                }
            }
        }
    }

    fn draw_status_bar(state: &UIState, log: &mut StatusLog, layout: Rect, frame: &mut Frame<B>) {
        use super::StatusBarState;

        match &state.status_bar_state {
            StatusBarState::Log => {
                log.adjust_to_size(layout, true);

                Paragraph::new(log.draw_items_iter())
                    .block(
                        Block::default()
                            .title("Status [':' for command entry]")
                            .borders(Borders::ALL),
                    )
                    .wrap(true)
                    .render(frame, layout);
            }
            StatusBarState::CommandPrompt(prompt) => {
                Paragraph::new(prompt.draw_items().iter())
                    .block(
                        Block::default()
                            .title("Enter Command")
                            .borders(Borders::ALL),
                    )
                    .wrap(true)
                    .render(frame, layout);
            }
        }
    }
}

pub type TermionBackend = backend::TermionBackend<RawTerminal<io::Stdout>>;

impl<'a> UI<'a, TermionBackend> {
    pub fn init() -> Result<UI<'a, TermionBackend>> {
        let stdout = io::stdout().into_raw_mode().context(err::IO)?;
        let backend = TermionBackend::new(stdout);
        let mut terminal = Terminal::new(backend).context(err::IO)?;

        terminal.clear().context(err::IO)?;
        terminal.hide_cursor().context(err::IO)?;

        Ok(UI {
            terminal,
            status_log: StatusLog::new(),
        })
    }
}

pub enum Event {
    Input(Key),
    Tick,
}

pub struct Events(mpsc::Receiver<Event>);

impl Events {
    pub fn new(tick_rate: Duration) -> Events {
        let (tx, rx) = mpsc::channel();

        Events::spawn_key_handler(tx.clone());
        Events::spawn_tick_handler(tick_rate, tx);

        Events(rx)
    }

    fn spawn_key_handler(tx: mpsc::Sender<Event>) -> thread::JoinHandle<()> {
        let stdin = io::stdin();

        thread::spawn(move || {
            for event in stdin.keys() {
                if let Ok(key) = event {
                    tx.send(Event::Input(key)).unwrap();
                }
            }
        })
    }

    fn spawn_tick_handler(tick_rate: Duration, tx: mpsc::Sender<Event>) -> thread::JoinHandle<()> {
        let tick_rate = tick_rate
            .to_std()
            .unwrap_or_else(|_| std::time::Duration::from_secs(1));

        thread::spawn(move || loop {
            thread::sleep(tick_rate);
            tx.send(Event::Tick).unwrap();
        })
    }

    pub fn next(&self) -> Result<Event> {
        self.0.recv().context(err::MPSCRecv)
    }
}
<commit_msg>anup: display help message when no series are present<commit_after>use super::component::log::StatusLog;
use super::{SeriesState, UIState, WatchState};
use crate::err::{self, Result};
use crate::util;
use anime::remote::ScoreParser;
use chrono::{Duration, Utc};
use smallvec::SmallVec;
use snafu::ResultExt;
use std::borrow::Cow;
use std::io;
use std::sync::mpsc;
use std::thread;
use termion::event::Key;
use termion::input::TermRead;
use termion::raw::{IntoRawMode, RawTerminal};
use tui::backend::{self, Backend};
use tui::layout::{Alignment, Constraint, Direction, Layout, Rect};
use tui::style::{Color, Modifier, Style};
use tui::terminal::{Frame, Terminal};
use tui::widgets::{Block, Borders, Paragraph, SelectableList, Text, Widget};

pub struct UI<'a, B>
where
    B: Backend,
{
    terminal: Terminal<B>,
    pub status_log: StatusLog<'a>,
}

macro_rules! create_stat_list {
    ($($header:expr => $value:expr),+) => {
        [$(
            create_stat_list!(h $header),
            create_stat_list!(v $header.len(), $value),
        )+]
    };

    (h $header:expr) => {
        Text::styled(format!("{}\n", $header), Style::default().modifier(Modifier::BOLD))
    };

    (v $len:expr, $value:expr) => {
        Text::styled(format!("{:^width$}\n\n", $value, width = $len), Style::default().modifier(Modifier::ITALIC))
    };
}

impl<'a, B> UI<'a, B>
where
    B: Backend,
{
    pub fn clear(&mut self) -> Result<()> {
        self.terminal.clear().context(err::IO)
    }

    pub fn draw<S>(&mut self, state: &UIState, score_parser: &S) -> Result<()>
    where
        S: ScoreParser + ?Sized,
    {
        let status_log = &mut self.status_log;

        self.terminal
            .draw(|mut frame| {
                // Top panels for series information
                let horiz_splitter = Layout::default()
                    .direction(Direction::Horizontal)
                    .constraints([Constraint::Min(20), Constraint::Percentage(70)].as_ref())
                    .split(frame.size());

                UI::draw_top_panels(state, &horiz_splitter, &mut frame);

                // Series info panel vertical splitter
                let info_panel_splitter = Layout::default()
                    .direction(Direction::Vertical)
                    .constraints([Constraint::Percentage(80), Constraint::Percentage(20)].as_ref())
                    .split(horiz_splitter[1]);

                UI::draw_info_panel(state, score_parser, &info_panel_splitter, &mut frame);
                UI::draw_status_bar(state, status_log, info_panel_splitter[1], &mut frame);
            })
            .context(err::IO)
    }

    fn draw_top_panels(state: &UIState, layout: &[Rect], frame: &mut Frame<B>) {
        let series_names = state
            .series
            .iter()
            .map(|series| &series.inner.nickname)
            .collect::<SmallVec<[_; 8]>>();

        let mut series_list = SelectableList::default()
            .block(Block::default().title("Series").borders(Borders::ALL))
            .items(&series_names)
            .select(Some(state.selected_series))
            .style(Style::default().fg(Color::White))
            .highlight_style(Style::default().fg(Color::Green).modifier(Modifier::ITALIC))
            .highlight_symbol(">");

        series_list.render(frame, layout[0]);
    }

    fn draw_info_panel<S>(state: &UIState, score_parser: &S, layout: &[Rect], frame: &mut Frame<B>)
    where
        S: ScoreParser + ?Sized,
    {
        Block::default()
            .title("Info")
            .borders(Borders::ALL)
            .render(frame, layout[0]);

        let info_layout = Layout::default()
            .direction(Direction::Vertical)
            .constraints(
                [
                    Constraint::Length(4),
                    Constraint::Percentage(70),
                    Constraint::Length(4),
                ]
                .as_ref(),
            )
            .margin(2)
            .split(layout[0]);

        match state.cur_series() {
            Some(series) => UI::draw_series_info(series, score_parser, &info_layout, frame),
            None => {
                let header =
                    Text::styled("No Series Found", Style::default().modifier(Modifier::BOLD));

                Paragraph::new([header].iter())
                    .alignment(Alignment::Center)
                    .render(frame, info_layout[0]);

                let body = Text::raw(
                    "Add one by launching the program with a \
                    \nkeyword similar to the series name on disk. \

                    \n\nFor example: assuming the path \"~/anime/Ooga Booga\" \
                    \nexists, launching the program with the keyword 'booga' \
                    \nwill add it to the series list. \

                    \n\nYou can also use a non-similar keyword along with \
                    \nthe -p flag to manually specify the path to the series. \

                    \n\nNote that by default, the program will look for a series \
                    \nin \"~/anime/\". You can change this in the config file.",
                );

                Paragraph::new([body].iter())
                    .alignment(Alignment::Center)
                    .render(frame, info_layout[1]);
            }
        }
    }

    fn draw_series_info<S>(
        series: &SeriesState,
        score_parser: &S,
        info_layout: &[Rect],
        frame: &mut Frame<B>,
    ) where
        S: ScoreParser + ?Sized,
    {
        let info = &series.inner.info;
        let entry = &series.inner.entry;

        // Series title
        {
            let text_items = {
                let mut items = SmallVec::<[_; 2]>::new();

                items.push(Text::styled(
                    &info.title.preferred,
                    Style::default().modifier(Modifier::BOLD),
                ));

                if entry.needs_sync() {
                    items.push(Text::styled(
                        " [*]",
                        Style::default().modifier(Modifier::ITALIC),
                    ));
                }

                items
            };

            Paragraph::new(text_items.iter())
                .alignment(Alignment::Center)
                .render(frame, info_layout[0]);
        }

        // Items in panel
        let stat_layout = Layout::default()
            .direction(Direction::Horizontal)
            .constraints(
                [
                    Constraint::Percentage(33),
                    Constraint::Percentage(33),
                    Constraint::Percentage(33),
                ]
                .as_ref(),
            )
            .split(info_layout[1]);

        {
            let left_items = create_stat_list!(
                "Watch Time" => {
                    let watch_time_mins = info.episodes * info.episode_length;
                    util::hm_from_mins(watch_time_mins as f32)
                },
                "Time Left" => {
                    let eps_left = info.episodes - entry.watched_eps().min(info.episodes);
                    let time_left_mins = eps_left * info.episode_length;

                    util::hm_from_mins(time_left_mins as f32)
                },
                "Episode Length" => format!("{}M", info.episode_length)
            );

            Paragraph::new(left_items.iter())
                .alignment(Alignment::Center)
                .render(frame, stat_layout[0]);
        }

        {
            let center_items = create_stat_list!(
                "Progress" => format!("{}|{}", entry.watched_eps(), info.episodes),
                "Score" => match entry.score() {
                    Some(score) => score_parser.score_to_str(score),
                    None => "??".into(),
                },
                "Status" => entry.status()
            );

            Paragraph::new(center_items.iter())
                .alignment(Alignment::Center)
                .render(frame, stat_layout[1]);
        }

        {
            let right_items = create_stat_list!(
                "Start Date" => match entry.start_date() {
                    Some(date) => format!("{}", date.format("%D")).into(),
                    None => Cow::Borrowed("??"),
                },
                "Finish Date" => match entry.end_date() {
                    Some(date) => format!("{}", date.format("%D")).into(),
                    None => Cow::Borrowed("??"),
                },
                "Rewatched" => entry.times_rewatched()
            );

            Paragraph::new(right_items.iter())
                .alignment(Alignment::Center)
                .render(frame, stat_layout[2]);
        }

        // Watch time needed indicator at bottom
        match series.watch_state {
            WatchState::Idle => (),
            WatchState::Watching(progress_time, _) => {
                let watch_time = progress_time - Utc::now();
                let watch_secs = watch_time.num_seconds();

                if watch_secs > 0 {
                    let remaining_mins = watch_secs as f32 / 60.0;

                    let text_str = format!(
                        "{} Remaining Until Progression",
                        util::ms_from_mins(remaining_mins)
                    );

                    let text = Text::styled(text_str, Style::default().modifier(Modifier::BOLD));

                    Paragraph::new([text].iter())
                        .alignment(Alignment::Center)
                        .render(frame, info_layout[2]);
                }
            }
        }
    }

    fn draw_status_bar(state: &UIState, log: &mut StatusLog, layout: Rect, frame: &mut Frame<B>) {
        use super::StatusBarState;

        match &state.status_bar_state {
            StatusBarState::Log => {
                log.adjust_to_size(layout, true);

                Paragraph::new(log.draw_items_iter())
                    .block(
                        Block::default()
                            .title("Status [':' for command entry]")
                            .borders(Borders::ALL),
                    )
                    .wrap(true)
                    .render(frame, layout);
            }
            StatusBarState::CommandPrompt(prompt) => {
                Paragraph::new(prompt.draw_items().iter())
                    .block(
                        Block::default()
                            .title("Enter Command")
                            .borders(Borders::ALL),
                    )
                    .wrap(true)
                    .render(frame, layout);
            }
        }
    }
}

pub type TermionBackend = backend::TermionBackend<RawTerminal<io::Stdout>>;

impl<'a> UI<'a, TermionBackend> {
    pub fn init() -> Result<UI<'a, TermionBackend>> {
        let stdout = io::stdout().into_raw_mode().context(err::IO)?;
        let backend = TermionBackend::new(stdout);
        let mut terminal = Terminal::new(backend).context(err::IO)?;

        terminal.clear().context(err::IO)?;
        terminal.hide_cursor().context(err::IO)?;

        Ok(UI {
            terminal,
            status_log: StatusLog::new(),
        })
    }
}

pub enum Event {
    Input(Key),
    Tick,
}

pub struct Events(mpsc::Receiver<Event>);

impl Events {
    pub fn new(tick_rate: Duration) -> Events {
        let (tx, rx) = mpsc::channel();

        Events::spawn_key_handler(tx.clone());
        Events::spawn_tick_handler(tick_rate, tx);

        Events(rx)
    }

    fn spawn_key_handler(tx: mpsc::Sender<Event>) -> thread::JoinHandle<()> {
        let stdin = io::stdin();

        thread::spawn(move || {
            for event in stdin.keys() {
                if let Ok(key) = event {
                    tx.send(Event::Input(key)).unwrap();
                }
            }
        })
    }

    fn spawn_tick_handler(tick_rate: Duration, tx: mpsc::Sender<Event>) -> thread::JoinHandle<()> {
        let tick_rate = tick_rate
            .to_std()
            .unwrap_or_else(|_| std::time::Duration::from_secs(1));

        thread::spawn(move || loop {
            thread::sleep(tick_rate);
            tx.send(Event::Tick).unwrap();
        })
    }

    pub fn next(&self) -> Result<Event> {
        self.0.recv().context(err::MPSCRecv)
    }
}
<|endoftext|>


<commit_before>//! This module contains the high-level DICOM abstraction trait.
//! At this level, objects are comparable to a dictionary of elements,
//! in which some of them can have DICOM objects themselves.
//! The end user should prefer using this abstraction when dealing with DICOM objects.
//!
//! # Examples
//!
//! ```no_run
//! use dicom_object::open_file;
//! # use dicom_object::Result;
//! # fn foo() -> Result<()> {
//! let obj = open_file("0001.dcm")?;
//! let patient_name = obj.element_by_name("PatientName")?.to_str()?;
//! let modality = obj.element_by_name("Modality")?.to_str()?;
//! # Ok(())
//! # }
//! ```
//!
//! Fetching an element by tag:
//!
//! ```
//! # use dicom_object::{DicomObject, Result, Tag};
//! # fn something<T: DicomObject>(obj: T) -> Result<()> {
//! let e = obj.element(Tag(0x0002, 0x0002))?;
//! # Ok(())
//! # }
//! ```
//!
extern crate byteordered;
extern crate dicom_core;
extern crate dicom_parser;
extern crate dicom_dictionary_std;
extern crate itertools;
extern crate smallvec;

pub mod file;
pub mod mem;
pub mod meta;
pub mod pixeldata;

mod util;

pub use dicom_dictionary_std::StandardDataDictionary;
pub use dicom_core::Tag;
pub use crate::file::{from_reader, open_file};
pub use crate::meta::DicomMetaTable;
pub use dicom_parser::error::{Result, Error};

pub type DefaultDicomObject = mem::InMemDicomObject<StandardDataDictionary>;

use dicom_core::header::Header;

/// Trait type for a DICOM object.
/// This is a high-level abstraction where an object is accessed and
/// manipulated as dictionary of entries indexed by tags, which in
/// turn may contain a DICOM object.
///
/// This trait interface is experimental and prone to sudden changes.
pub trait DicomObject {
    type Element: Header; // TODO change constraint

    /// Retrieve a particular DICOM element by its tag.
    fn element(&self, tag: Tag) -> Result<Self::Element>;

    /// Retrieve a particular DICOM element by its name.
    fn element_by_name(&self, name: &str) -> Result<Self::Element>;

    // TODO moar
}

/** A root DICOM object contains additional meta information about the object
 * (such as the DICOM file's meta header).
 */
#[derive(Debug, Clone, PartialEq)]
pub struct RootDicomObject<T> {
    meta: DicomMetaTable,
    obj: T,
}

impl<T> RootDicomObject<T> {
    /// Retrieve the processed meta header table.
    pub fn meta(&self) -> &DicomMetaTable {
        &self.meta
    }
}

impl<T> ::std::ops::Deref for RootDicomObject<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.obj
    }
}

impl<T> ::std::ops::DerefMut for RootDicomObject<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.obj
    }
}

impl<T> DicomObject for RootDicomObject<T>
where
    T: DicomObject,
{
    type Element = <T as DicomObject>::Element;

    fn element(&self, tag: Tag) -> Result<Self::Element> {
        self.obj.element(tag)
    }

    fn element_by_name(&self, name: &str) -> Result<Self::Element> {
        self.obj.element_by_name(name)
    }
}

impl<'a, T: 'a> DicomObject for &'a RootDicomObject<T>
where
    T: DicomObject,
{
    type Element = <T as DicomObject>::Element;

    fn element(&self, tag: Tag) -> Result<Self::Element> {
        self.obj.element(tag)
    }

    fn element_by_name(&self, name: &str) -> Result<Self::Element> {
        self.obj.element_by_name(name)
    }
}

#[cfg(test)]
mod tests {
}
<commit_msg>[object] make module loader part of object<commit_after>//! This module contains the high-level DICOM abstraction trait.
//! At this level, objects are comparable to a dictionary of elements,
//! in which some of them can have DICOM objects themselves.
//! The end user should prefer using this abstraction when dealing with DICOM objects.
//!
//! # Examples
//!
//! ```no_run
//! use dicom_object::open_file;
//! # use dicom_object::Result;
//! # fn foo() -> Result<()> {
//! let obj = open_file("0001.dcm")?;
//! let patient_name = obj.element_by_name("PatientName")?.to_str()?;
//! let modality = obj.element_by_name("Modality")?.to_str()?;
//! # Ok(())
//! # }
//! ```
//!
//! Fetching an element by tag:
//!
//! ```
//! # use dicom_object::{DicomObject, Result, Tag};
//! # fn something<T: DicomObject>(obj: T) -> Result<()> {
//! let e = obj.element(Tag(0x0002, 0x0002))?;
//! # Ok(())
//! # }
//! ```
//!
extern crate byteordered;
extern crate dicom_core;
extern crate dicom_parser;
extern crate dicom_dictionary_std;
extern crate itertools;
extern crate smallvec;

pub mod file;
pub mod mem;
pub mod meta;
pub mod pixeldata;

mod util;
mod loader;

pub use dicom_dictionary_std::StandardDataDictionary;
pub use dicom_core::Tag;
pub use crate::file::{from_reader, open_file};
pub use crate::meta::DicomMetaTable;
pub use dicom_parser::error::{Result, Error};

pub type DefaultDicomObject = mem::InMemDicomObject<StandardDataDictionary>;

use dicom_core::header::Header;

/// Trait type for a DICOM object.
/// This is a high-level abstraction where an object is accessed and
/// manipulated as dictionary of entries indexed by tags, which in
/// turn may contain a DICOM object.
///
/// This trait interface is experimental and prone to sudden changes.
pub trait DicomObject {
    type Element: Header; // TODO change constraint

    /// Retrieve a particular DICOM element by its tag.
    fn element(&self, tag: Tag) -> Result<Self::Element>;

    /// Retrieve a particular DICOM element by its name.
    fn element_by_name(&self, name: &str) -> Result<Self::Element>;

    // TODO moar
}

/** A root DICOM object contains additional meta information about the object
 * (such as the DICOM file's meta header).
 */
#[derive(Debug, Clone, PartialEq)]
pub struct RootDicomObject<T> {
    meta: DicomMetaTable,
    obj: T,
}

impl<T> RootDicomObject<T> {
    /// Retrieve the processed meta header table.
    pub fn meta(&self) -> &DicomMetaTable {
        &self.meta
    }
}

impl<T> ::std::ops::Deref for RootDicomObject<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.obj
    }
}

impl<T> ::std::ops::DerefMut for RootDicomObject<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.obj
    }
}

impl<T> DicomObject for RootDicomObject<T>
where
    T: DicomObject,
{
    type Element = <T as DicomObject>::Element;

    fn element(&self, tag: Tag) -> Result<Self::Element> {
        self.obj.element(tag)
    }

    fn element_by_name(&self, name: &str) -> Result<Self::Element> {
        self.obj.element_by_name(name)
    }
}

impl<'a, T: 'a> DicomObject for &'a RootDicomObject<T>
where
    T: DicomObject,
{
    type Element = <T as DicomObject>::Element;

    fn element(&self, tag: Tag) -> Result<Self::Element> {
        self.obj.element(tag)
    }

    fn element_by_name(&self, name: &str) -> Result<Self::Element> {
        self.obj.element_by_name(name)
    }
}

#[cfg(test)]
mod tests {
}
<|endoftext|>