<commit_before>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![unstable(feature = "allocator_api",
            reason = "the precise API and guarantees it provides may be tweaked \
                      slightly, especially to possibly take into account the \
                      types being stored to make room for a future \
                      tracing garbage collector",
            issue = "32838")]

use core::intrinsics::{min_align_of_val, size_of_val};
use core::mem::{self, ManuallyDrop};
use core::usize;

pub use allocator::*;
#[doc(hidden)]
pub mod __core {
    pub use core::*;
}

extern "Rust" {
    #[allocator]
    #[rustc_allocator_nounwind]
    fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8;
    #[cold]
    #[rustc_allocator_nounwind]
    fn __rust_oom(err: *const u8) -> !;
    #[rustc_allocator_nounwind]
    fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
    #[rustc_allocator_nounwind]
    fn __rust_usable_size(layout: *const u8,
                          min: *mut usize,
                          max: *mut usize);
    #[rustc_allocator_nounwind]
    fn __rust_realloc(ptr: *mut u8,
                      old_size: usize,
                      old_align: usize,
                      new_size: usize,
                      new_align: usize,
                      err: *mut u8) -> *mut u8;
    #[rustc_allocator_nounwind]
    fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8;
    #[rustc_allocator_nounwind]
    fn __rust_alloc_excess(size: usize,
                           align: usize,
                           excess: *mut usize,
                           err: *mut u8) -> *mut u8;
    #[rustc_allocator_nounwind]
    fn __rust_realloc_excess(ptr: *mut u8,
                             old_size: usize,
                             old_align: usize,
                             new_size: usize,
                             new_align: usize,
                             excess: *mut usize,
                             err: *mut u8) -> *mut u8;
    #[rustc_allocator_nounwind]
    fn __rust_grow_in_place(ptr: *mut u8,
                            old_size: usize,
                            old_align: usize,
                            new_size: usize,
                            new_align: usize) -> u8;
    #[rustc_allocator_nounwind]
    fn __rust_shrink_in_place(ptr: *mut u8,
                              old_size: usize,
                              old_align: usize,
                              new_size: usize,
                              new_align: usize) -> u8;
}

#[derive(Copy, Clone, Default, Debug)]
pub struct Heap;

unsafe impl Alloc for Heap {
    #[inline]
    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
        let ptr = __rust_alloc(layout.size(),
                               layout.align(),
                               &mut *err as *mut AllocErr as *mut u8);
        if ptr.is_null() {
            Err(ManuallyDrop::into_inner(err))
        } else {
            Ok(ptr)
        }
    }

    #[inline]
    #[cold]
    fn oom(&mut self, err: AllocErr) -> ! {
        unsafe {
            __rust_oom(&err as *const AllocErr as *const u8)
        }
    }

    #[inline]
    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
        __rust_dealloc(ptr, layout.size(), layout.align())
    }

    #[inline]
    fn usable_size(&self, layout: &Layout) -> (usize, usize) {
        let mut min = 0;
        let mut max = 0;
        unsafe {
            __rust_usable_size(layout as *const Layout as *const u8,
                               &mut min,
                               &mut max);
        }
        (min, max)
    }

    #[inline]
    unsafe fn realloc(&mut self,
                      ptr: *mut u8,
                      layout: Layout,
                      new_layout: Layout)
                      -> Result<*mut u8, AllocErr>
    {
        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
        let ptr = __rust_realloc(ptr,
                                 layout.size(),
                                 layout.align(),
                                 new_layout.size(),
                                 new_layout.align(),
                                 &mut *err as *mut AllocErr as *mut u8);
        if ptr.is_null() {
            Err(ManuallyDrop::into_inner(err))
        } else {
            mem::forget(err);
            Ok(ptr)
        }
    }

    #[inline]
    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
        let ptr = __rust_alloc_zeroed(layout.size(),
                                      layout.align(),
                                      &mut *err as *mut AllocErr as *mut u8);
        if ptr.is_null() {
            Err(ManuallyDrop::into_inner(err))
        } else {
            Ok(ptr)
        }
    }

    #[inline]
    unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
        let mut size = 0;
        let ptr = __rust_alloc_excess(layout.size(),
                                      layout.align(),
                                      &mut size,
                                      &mut *err as *mut AllocErr as *mut u8);
        if ptr.is_null() {
            Err(ManuallyDrop::into_inner(err))
        } else {
            Ok(Excess(ptr, size))
        }
    }

    #[inline]
    unsafe fn realloc_excess(&mut self,
                             ptr: *mut u8,
                             layout: Layout,
                             new_layout: Layout) -> Result<Excess, AllocErr> {
        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
        let mut size = 0;
        let ptr = __rust_realloc_excess(ptr,
                                        layout.size(),
                                        layout.align(),
                                        new_layout.size(),
                                        new_layout.align(),
                                        &mut size,
                                        &mut *err as *mut AllocErr as *mut u8);
        if ptr.is_null() {
            Err(ManuallyDrop::into_inner(err))
        } else {
            Ok(Excess(ptr, size))
        }
    }

    #[inline]
    unsafe fn grow_in_place(&mut self,
                            ptr: *mut u8,
                            layout: Layout,
                            new_layout: Layout)
                            -> Result<(), CannotReallocInPlace>
    {
        debug_assert!(new_layout.size() >= layout.size());
        debug_assert!(new_layout.align() == layout.align());
        let ret = __rust_grow_in_place(ptr,
                                       layout.size(),
                                       layout.align(),
                                       new_layout.size(),
                                       new_layout.align());
        if ret != 0 {
            Ok(())
        } else {
            Err(CannotReallocInPlace)
        }
    }

    #[inline]
    unsafe fn shrink_in_place(&mut self,
                              ptr: *mut u8,
                              layout: Layout,
                              new_layout: Layout) -> Result<(), CannotReallocInPlace> {
        debug_assert!(new_layout.size() <= layout.size());
        debug_assert!(new_layout.align() == layout.align());
        let ret = __rust_shrink_in_place(ptr,
                                         layout.size(),
                                         layout.align(),
                                         new_layout.size(),
                                         new_layout.align());
        if ret != 0 {
            Ok(())
        } else {
            Err(CannotReallocInPlace)
        }
    }
}

/// An arbitrary non-null address to represent zero-size allocations.
///
/// This preserves the non-null invariant for types like `Box<T>`. The address
/// may overlap with non-zero-size memory allocations.
#[rustc_deprecated(since = "1.19.0", reason = "Use Unique/NonNull::empty() instead")]
#[unstable(feature = "heap_api", issue = "27700")]
pub const EMPTY: *mut () = 1 as *mut ();

/// The allocator for unique pointers.
// This function must not unwind. If it does, MIR trans will fail.
#[cfg(not(test))]
#[lang = "exchange_malloc"]
#[inline]
unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
    if size == 0 {
        align as *mut u8
    } else {
        let layout = Layout::from_size_align_unchecked(size, align);
        Heap.alloc(layout).unwrap_or_else(|err| {
            Heap.oom(err)
        })
    }
}

#[cfg_attr(not(test), lang = "box_free")]
#[inline]
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
    let size = size_of_val(&*ptr);
    let align = min_align_of_val(&*ptr);
    // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
    if size != 0 {
        let layout = Layout::from_size_align_unchecked(size, align);
        Heap.dealloc(ptr as *mut u8, layout);
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;
    use boxed::Box;
    use heap::{Heap, Alloc, Layout};

    #[test]
    fn allocate_zeroed() {
        unsafe {
            let layout = Layout::from_size_align(1024, 1).unwrap();
            let ptr = Heap.alloc_zeroed(layout.clone())
                .unwrap_or_else(|e| Heap.oom(e));

            let end = ptr.offset(layout.size() as isize);
            let mut i = ptr;
            while i < end {
                assert_eq!(*i, 0);
                i = i.offset(1);
            }
            Heap.dealloc(ptr, layout);
        }
    }

    #[bench]
    fn alloc_owned_small(b: &mut Bencher) {
        b.iter(|| {
            let _: Box<_> = box 10;
        })
    }
}
<commit_msg>Rollup merge of #49082 - SimonSapin:mu, r=alexcrichton<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![unstable(feature = "allocator_api",
            reason = "the precise API and guarantees it provides may be tweaked \
                      slightly, especially to possibly take into account the \
                      types being stored to make room for a future \
                      tracing garbage collector",
            issue = "32838")]

use core::intrinsics::{min_align_of_val, size_of_val};
use core::mem::{self, ManuallyDrop};
use core::usize;

pub use allocator::*;
#[doc(hidden)]
pub mod __core {
    pub use core::*;
}

extern "Rust" {
    #[allocator]
    #[rustc_allocator_nounwind]
    fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8;
    #[cold]
    #[rustc_allocator_nounwind]
    fn __rust_oom(err: *const u8) -> !;
    #[rustc_allocator_nounwind]
    fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
    #[rustc_allocator_nounwind]
    fn __rust_usable_size(layout: *const u8,
                          min: *mut usize,
                          max: *mut usize);
    #[rustc_allocator_nounwind]
    fn __rust_realloc(ptr: *mut u8,
                      old_size: usize,
                      old_align: usize,
                      new_size: usize,
                      new_align: usize,
                      err: *mut u8) -> *mut u8;
    #[rustc_allocator_nounwind]
    fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8;
    #[rustc_allocator_nounwind]
    fn __rust_alloc_excess(size: usize,
                           align: usize,
                           excess: *mut usize,
                           err: *mut u8) -> *mut u8;
    #[rustc_allocator_nounwind]
    fn __rust_realloc_excess(ptr: *mut u8,
                             old_size: usize,
                             old_align: usize,
                             new_size: usize,
                             new_align: usize,
                             excess: *mut usize,
                             err: *mut u8) -> *mut u8;
    #[rustc_allocator_nounwind]
    fn __rust_grow_in_place(ptr: *mut u8,
                            old_size: usize,
                            old_align: usize,
                            new_size: usize,
                            new_align: usize) -> u8;
    #[rustc_allocator_nounwind]
    fn __rust_shrink_in_place(ptr: *mut u8,
                              old_size: usize,
                              old_align: usize,
                              new_size: usize,
                              new_align: usize) -> u8;
}

#[derive(Copy, Clone, Default, Debug)]
pub struct Heap;

unsafe impl Alloc for Heap {
    #[inline]
    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
        let ptr = __rust_alloc(layout.size(),
                               layout.align(),
                               &mut *err as *mut AllocErr as *mut u8);
        if ptr.is_null() {
            Err(ManuallyDrop::into_inner(err))
        } else {
            Ok(ptr)
        }
    }

    #[inline]
    #[cold]
    fn oom(&mut self, err: AllocErr) -> ! {
        unsafe {
            __rust_oom(&err as *const AllocErr as *const u8)
        }
    }

    #[inline]
    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
        __rust_dealloc(ptr, layout.size(), layout.align())
    }

    #[inline]
    fn usable_size(&self, layout: &Layout) -> (usize, usize) {
        let mut min = 0;
        let mut max = 0;
        unsafe {
            __rust_usable_size(layout as *const Layout as *const u8,
                               &mut min,
                               &mut max);
        }
        (min, max)
    }

    #[inline]
    unsafe fn realloc(&mut self,
                      ptr: *mut u8,
                      layout: Layout,
                      new_layout: Layout)
                      -> Result<*mut u8, AllocErr>
    {
        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
        let ptr = __rust_realloc(ptr,
                                 layout.size(),
                                 layout.align(),
                                 new_layout.size(),
                                 new_layout.align(),
                                 &mut *err as *mut AllocErr as *mut u8);
        if ptr.is_null() {
            Err(ManuallyDrop::into_inner(err))
        } else {
            mem::forget(err);
            Ok(ptr)
        }
    }

    #[inline]
    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
        let ptr = __rust_alloc_zeroed(layout.size(),
                                      layout.align(),
                                      &mut *err as *mut AllocErr as *mut u8);
        if ptr.is_null() {
            Err(ManuallyDrop::into_inner(err))
        } else {
            Ok(ptr)
        }
    }

    #[inline]
    unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
        let mut size = 0;
        let ptr = __rust_alloc_excess(layout.size(),
                                      layout.align(),
                                      &mut size,
                                      &mut *err as *mut AllocErr as *mut u8);
        if ptr.is_null() {
            Err(ManuallyDrop::into_inner(err))
        } else {
            Ok(Excess(ptr, size))
        }
    }

    #[inline]
    unsafe fn realloc_excess(&mut self,
                             ptr: *mut u8,
                             layout: Layout,
                             new_layout: Layout) -> Result<Excess, AllocErr> {
        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
        let mut size = 0;
        let ptr = __rust_realloc_excess(ptr,
                                        layout.size(),
                                        layout.align(),
                                        new_layout.size(),
                                        new_layout.align(),
                                        &mut size,
                                        &mut *err as *mut AllocErr as *mut u8);
        if ptr.is_null() {
            Err(ManuallyDrop::into_inner(err))
        } else {
            Ok(Excess(ptr, size))
        }
    }

    #[inline]
    unsafe fn grow_in_place(&mut self,
                            ptr: *mut u8,
                            layout: Layout,
                            new_layout: Layout)
                            -> Result<(), CannotReallocInPlace>
    {
        debug_assert!(new_layout.size() >= layout.size());
        debug_assert!(new_layout.align() == layout.align());
        let ret = __rust_grow_in_place(ptr,
                                       layout.size(),
                                       layout.align(),
                                       new_layout.size(),
                                       new_layout.align());
        if ret != 0 {
            Ok(())
        } else {
            Err(CannotReallocInPlace)
        }
    }

    #[inline]
    unsafe fn shrink_in_place(&mut self,
                              ptr: *mut u8,
                              layout: Layout,
                              new_layout: Layout) -> Result<(), CannotReallocInPlace> {
        debug_assert!(new_layout.size() <= layout.size());
        debug_assert!(new_layout.align() == layout.align());
        let ret = __rust_shrink_in_place(ptr,
                                         layout.size(),
                                         layout.align(),
                                         new_layout.size(),
                                         new_layout.align());
        if ret != 0 {
            Ok(())
        } else {
            Err(CannotReallocInPlace)
        }
    }
}

/// The allocator for unique pointers.
// This function must not unwind. If it does, MIR trans will fail.
#[cfg(not(test))]
#[lang = "exchange_malloc"]
#[inline]
unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
    if size == 0 {
        align as *mut u8
    } else {
        let layout = Layout::from_size_align_unchecked(size, align);
        Heap.alloc(layout).unwrap_or_else(|err| {
            Heap.oom(err)
        })
    }
}

#[cfg_attr(not(test), lang = "box_free")]
#[inline]
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
    let size = size_of_val(&*ptr);
    let align = min_align_of_val(&*ptr);
    // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
    if size != 0 {
        let layout = Layout::from_size_align_unchecked(size, align);
        Heap.dealloc(ptr as *mut u8, layout);
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;
    use boxed::Box;
    use heap::{Heap, Alloc, Layout};

    #[test]
    fn allocate_zeroed() {
        unsafe {
            let layout = Layout::from_size_align(1024, 1).unwrap();
            let ptr = Heap.alloc_zeroed(layout.clone())
                .unwrap_or_else(|e| Heap.oom(e));

            let end = ptr.offset(layout.size() as isize);
            let mut i = ptr;
            while i < end {
                assert_eq!(*i, 0);
                i = i.offset(1);
            }
            Heap.dealloc(ptr, layout);
        }
    }

    #[bench]
    fn alloc_owned_small(b: &mut Bencher) {
        b.iter(|| {
            let _: Box<_> = box 10;
        })
    }
}
<|endoftext|>


<commit_before>use fst::Streamer;
use std::mem;
use std::collections::BinaryHeap;
use fst::map::Keys;
use schema::Field;
use schema::Term;
use core::SegmentReader;
use std::cmp::Ordering;

#[derive(PartialEq, Eq, Debug)]
struct HeapItem {
    term: Term,
    segment_ord: usize,
}

impl PartialOrd for HeapItem {
    fn partial_cmp(&self, other: &HeapItem) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for HeapItem {
    fn cmp(&self, other: &HeapItem) -> Ordering {
        (&other.term, &other.segment_ord).cmp(&(&self.term, &self.segment_ord))
    }
}

/// Given a list of sorted term streams,
/// returns an iterator over sorted unique terms.
///
/// The item yield is actually a pair with
/// - the term
/// - a slice with the ordinal of the segments containing
/// the terms.
pub struct TermIterator<'a> {
    key_streams: Vec<Keys<'a>>,
    heap: BinaryHeap<HeapItem>,
    // Buffer hosting the list of segment ordinals containing
    // the current term.
    current_term: Term,
    current_segment_ords: Vec<usize>,
}

impl<'a> TermIterator<'a> {
    fn new(key_streams: Vec<Keys<'a>>) -> TermIterator<'a> {
        let key_streams_len = key_streams.len();
        let mut term_iterator = TermIterator {
            key_streams: key_streams,
            heap: BinaryHeap::new(),
            current_term: Term::from_field_text(Field(0), ""),
            current_segment_ords: vec![],
        };
        for segment_ord in 0..key_streams_len {
            term_iterator.push_next_segment_el(segment_ord);
        }
        term_iterator
    }

    fn push_next_segment_el(&mut self, segment_ord: usize) {
        self.current_segment_ords.push(segment_ord);
        if let Some(term) = self.key_streams[segment_ord].next() {
            self.heap.push(HeapItem {
                term: Term::from(term),
                segment_ord: segment_ord,
            });
        }
    }
}

impl<'a, 'f> Streamer<'a> for TermIterator<'f> {
    type Item = &'a Term;

    fn next(&'a mut self) -> Option<Self::Item> {
        self.current_segment_ords.clear();
        self.heap
            .pop()
            .map(move |mut head| {
                mem::swap(&mut self.current_term, &mut head.term);
                self.push_next_segment_el(head.segment_ord);
                loop {
                    match self.heap.peek() {
                        Some(&ref next_heap_it) if next_heap_it.term == self.current_term => {}
                        _ => { break; }
                    }
                    let next_heap_it = self.heap.pop().unwrap(); // safe : we peeked beforehand
                    self.push_next_segment_el(next_heap_it.segment_ord);
                }
                &self.current_term
            })
    }
}

impl<'a> From<&'a [SegmentReader]> for TermIterator<'a> {
    fn from(segment_readers: &'a [SegmentReader]) -> TermIterator<'a> {
        TermIterator::new(
            segment_readers
            .iter()
            .map(|reader| reader.term_infos().keys())
            .collect()
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use schema::{SchemaBuilder, Document, TEXT};
    use core::Index;

    #[test]
    fn test_term_iterator() {
        let mut schema_builder = SchemaBuilder::default();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let index = Index::create_in_ram(schema_builder.build());
        {
            let mut index_writer = index.writer_with_num_threads(1, 40_000_000).unwrap();
            {
                // writing the segment
                {
                    let mut doc = Document::default();
                    doc.add_text(text_field, "a b d f");
                    index_writer.add_document(doc).unwrap();
                }
                index_writer.commit().unwrap();
            }
            {
                // writing the segment
                {
                    let mut doc = Document::default();
                    doc.add_text(text_field, "a b c d f");
                    index_writer.add_document(doc).unwrap();
                }
                index_writer.commit().unwrap();
            }
            {
                // writing the segment
                {
                    let mut doc = Document::default();
                    doc.add_text(text_field, "e f");
                    index_writer.add_document(doc).unwrap();
                }
                index_writer.commit().unwrap();
            }
        }
        let searcher = index.searcher();
        let mut term_it = searcher.terms();
        let mut terms = String::new();
        while let Some(term) = term_it.next() {
            unsafe {
                terms.push_str(term.text());
            }
        }
        assert_eq!(terms, "abcdef");
    }

}<commit_msg>Issue #67   Removing afterwards.<commit_after>use fst::Streamer;
use std::mem;
use std::collections::BinaryHeap;
use fst::map::Keys;
use schema::Field;
use schema::Term;
use core::SegmentReader;
use std::cmp::Ordering;

#[derive(PartialEq, Eq, Debug)]
struct HeapItem {
    term: Term,
    segment_ord: usize,
}

impl PartialOrd for HeapItem {
    fn partial_cmp(&self, other: &HeapItem) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for HeapItem {
    fn cmp(&self, other: &HeapItem) -> Ordering {
        (&other.term, &other.segment_ord).cmp(&(&self.term, &self.segment_ord))
    }
}

/// Given a list of sorted term streams,
/// returns an iterator over sorted unique terms.
///
/// The item yield is actually a pair with
/// - the term
/// - a slice with the ordinal of the segments containing
/// the terms.
pub struct TermIterator<'a> {
    key_streams: Vec<Keys<'a>>,
    heap: BinaryHeap<HeapItem>,
    // Buffer hosting the list of segment ordinals containing
    // the current term.
    current_term: Term,
    current_segment_ords: Vec<usize>,
}

impl<'a> TermIterator<'a> {
    fn new(key_streams: Vec<Keys<'a>>) -> TermIterator<'a> {
        let key_streams_len = key_streams.len();
        TermIterator {
            key_streams: key_streams,
            heap: BinaryHeap::new(),
            current_term: Term::from_field_text(Field(0), ""),
            current_segment_ords: (0..key_streams_len).collect(),
        }
    }

    fn advance_segments(&mut self) {
        for segment_ord in self.current_segment_ords.drain(..) {
            if let Some(term) = self.key_streams[segment_ord].next() {
                self.heap.push(HeapItem {
                    term: Term::from(term),
                    segment_ord: segment_ord,
                });
            }
        }
    }
}

impl<'a, 'f> Streamer<'a> for TermIterator<'f> {
    type Item = &'a Term;

    fn next(&'a mut self) -> Option<Self::Item> {
        self.advance_segments();
        self.heap
            .pop()
            .map(move |mut head| {
                mem::swap(&mut self.current_term, &mut head.term);
                self.current_segment_ords.push(head.segment_ord);
                loop {
                    match self.heap.peek() {
                        Some(&ref next_heap_it) if next_heap_it.term == self.current_term => {}
                        _ => { break; }
                    }
                    let next_heap_it = self.heap.pop().unwrap(); // safe : we peeked beforehand
                    self.current_segment_ords.push(next_heap_it.segment_ord);
                }
                &self.current_term
            })
    }
}

impl<'a> From<&'a [SegmentReader]> for TermIterator<'a> {
    fn from(segment_readers: &'a [SegmentReader]) -> TermIterator<'a> {
        TermIterator::new(
            segment_readers
            .iter()
            .map(|reader| reader.term_infos().keys())
            .collect()
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use schema::{SchemaBuilder, Document, TEXT};
    use core::Index;

    #[test]
    fn test_term_iterator() {
        let mut schema_builder = SchemaBuilder::default();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let index = Index::create_in_ram(schema_builder.build());
        {
            let mut index_writer = index.writer_with_num_threads(1, 40_000_000).unwrap();
            {
                {
                    let mut doc = Document::default();
                    doc.add_text(text_field, "a b d f");
                    index_writer.add_document(doc).unwrap();
                }
                index_writer.commit().unwrap();
            }
            {
                {
                    let mut doc = Document::default();
                    doc.add_text(text_field, "a b c d f");
                    index_writer.add_document(doc).unwrap();
                }
                index_writer.commit().unwrap();
            }
            {
                {
                    let mut doc = Document::default();
                    doc.add_text(text_field, "e f");
                    index_writer.add_document(doc).unwrap();
                }
                index_writer.commit().unwrap();
            }
        }
        let searcher = index.searcher();
        let mut term_it = searcher.terms();
        let mut terms = String::new();
        while let Some(term) = term_it.next() {
            unsafe {
                terms.push_str(term.text());
            }
        }
        assert_eq!(terms, "abcdef");
    }

}<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Simple ANSI color library

#[allow(missing_doc)];

use core::prelude::*;

use core::io;

#[cfg(not(target_os = "win32"))] use core::os;
#[cfg(not(target_os = "win32"))] use terminfo::*;
#[cfg(not(target_os = "win32"))] use terminfo::searcher::open;
#[cfg(not(target_os = "win32"))] use terminfo::parser::compiled::parse;
#[cfg(not(target_os = "win32"))] use terminfo::parm::{expand, Number, Variables};

// FIXME (#2807): Windows support.

pub mod color {
    pub type Color = u16;

    pub static black:   Color = 0u16;
    pub static red:     Color = 1u16;
    pub static green:   Color = 2u16;
    pub static yellow:  Color = 3u16;
    pub static blue:    Color = 4u16;
    pub static magenta: Color = 5u16;
    pub static cyan:    Color = 6u16;
    pub static white:   Color = 7u16;

    pub static bright_black:   Color = 8u16;
    pub static bright_red:     Color = 9u16;
    pub static bright_green:   Color = 10u16;
    pub static bright_yellow:  Color = 11u16;
    pub static bright_blue:    Color = 12u16;
    pub static bright_magenta: Color = 13u16;
    pub static bright_cyan:    Color = 14u16;
    pub static bright_white:   Color = 15u16;
}

#[cfg(not(target_os = "win32"))]
pub struct Terminal {
    num_colors: u16,
    priv out: @io::Writer,
    priv ti: ~TermInfo
}

#[cfg(target_os = "win32")]
pub struct Terminal {
    num_colors: u16,
    priv out: @io::Writer,
}

#[cfg(not(target_os = "win32"))]
impl Terminal {
    pub fn new(out: @io::Writer) -> Result<Terminal, ~str> {
        let term = os::getenv("TERM");
        if term.is_none() {
            return Err(~"TERM environment variable undefined");
        }

        let entry = open(term.unwrap());
        if entry.is_err() {
            return Err(entry.unwrap_err());
        }

        let ti = parse(entry.unwrap(), false);
        if ti.is_err() {
            return Err(ti.unwrap_err());
        }

        let inf = ti.unwrap();
        let nc = if inf.strings.find_equiv(&("setaf")).is_some()
                 && inf.strings.find_equiv(&("setab")).is_some() {
                     inf.numbers.find_equiv(&("colors")).map_consume_default(0, |&n| n)
                 } else { 0 };

        return Ok(Terminal {out: out, ti: inf, num_colors: nc});
    }
    /// Sets the foreground color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    pub fn fg(&self, color: color::Color) {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            let s = expand(*self.ti.strings.find_equiv(&("setaf")).unwrap(),
                           [Number(color as int)], &mut Variables::new());
            if s.is_ok() {
                self.out.write(s.unwrap());
            } else {
                warn!("%s", s.unwrap_err());
            }
        }
    }
    /// Sets the background color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    pub fn bg(&self, color: color::Color) {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            let s = expand(*self.ti.strings.find_equiv(&("setab")).unwrap(),
                           [Number(color as int)], &mut Variables::new());
            if s.is_ok() {
                self.out.write(s.unwrap());
            } else {
                warn!("%s", s.unwrap_err());
            }
        }
    }
    pub fn reset(&self) {
        let mut vars = Variables::new();
        let s = do self.ti.strings.find_equiv(&("op"))
                       .map_consume_default(Err(~"can't find op")) |&op| {
                           expand(op, [], &mut vars)
                       };
        if s.is_ok() {
            self.out.write(s.unwrap());
        } else {
            warn!("%s", s.unwrap_err());
        }
    }

    priv fn dim_if_necessary(&self, color: color::Color) -> color::Color {
        if color >= self.num_colors && color >= 8 && color < 16 {
            color-8
        } else { color }
    }
}

#[cfg(target_os = "win32")]
impl Terminal {
    pub fn new(out: @io::Writer) -> Result<Terminal, ~str> {
        return Ok(Terminal {out: out, num_colors: 0});
    }

    pub fn fg(&self, _color: color::Color) {
    }

    pub fn bg(&self, _color: color::Color) {
    }

    pub fn reset(&self) {
    }
}
<commit_msg>Smarter warning in extra::term::Terminal.reset()<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Simple ANSI color library

#[allow(missing_doc)];

use core::prelude::*;

use core::io;

#[cfg(not(target_os = "win32"))] use core::os;
#[cfg(not(target_os = "win32"))] use terminfo::*;
#[cfg(not(target_os = "win32"))] use terminfo::searcher::open;
#[cfg(not(target_os = "win32"))] use terminfo::parser::compiled::parse;
#[cfg(not(target_os = "win32"))] use terminfo::parm::{expand, Number, Variables};

// FIXME (#2807): Windows support.

pub mod color {
    pub type Color = u16;

    pub static black:   Color = 0u16;
    pub static red:     Color = 1u16;
    pub static green:   Color = 2u16;
    pub static yellow:  Color = 3u16;
    pub static blue:    Color = 4u16;
    pub static magenta: Color = 5u16;
    pub static cyan:    Color = 6u16;
    pub static white:   Color = 7u16;

    pub static bright_black:   Color = 8u16;
    pub static bright_red:     Color = 9u16;
    pub static bright_green:   Color = 10u16;
    pub static bright_yellow:  Color = 11u16;
    pub static bright_blue:    Color = 12u16;
    pub static bright_magenta: Color = 13u16;
    pub static bright_cyan:    Color = 14u16;
    pub static bright_white:   Color = 15u16;
}

#[cfg(not(target_os = "win32"))]
pub struct Terminal {
    num_colors: u16,
    priv out: @io::Writer,
    priv ti: ~TermInfo
}

#[cfg(target_os = "win32")]
pub struct Terminal {
    num_colors: u16,
    priv out: @io::Writer,
}

#[cfg(not(target_os = "win32"))]
impl Terminal {
    pub fn new(out: @io::Writer) -> Result<Terminal, ~str> {
        let term = os::getenv("TERM");
        if term.is_none() {
            return Err(~"TERM environment variable undefined");
        }

        let entry = open(term.unwrap());
        if entry.is_err() {
            return Err(entry.unwrap_err());
        }

        let ti = parse(entry.unwrap(), false);
        if ti.is_err() {
            return Err(ti.unwrap_err());
        }

        let inf = ti.unwrap();
        let nc = if inf.strings.find_equiv(&("setaf")).is_some()
                 && inf.strings.find_equiv(&("setab")).is_some() {
                     inf.numbers.find_equiv(&("colors")).map_consume_default(0, |&n| n)
                 } else { 0 };

        return Ok(Terminal {out: out, ti: inf, num_colors: nc});
    }
    /// Sets the foreground color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    pub fn fg(&self, color: color::Color) {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            let s = expand(*self.ti.strings.find_equiv(&("setaf")).unwrap(),
                           [Number(color as int)], &mut Variables::new());
            if s.is_ok() {
                self.out.write(s.unwrap());
            } else {
                warn!("%s", s.unwrap_err());
            }
        }
    }
    /// Sets the background color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    pub fn bg(&self, color: color::Color) {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            let s = expand(*self.ti.strings.find_equiv(&("setab")).unwrap(),
                           [Number(color as int)], &mut Variables::new());
            if s.is_ok() {
                self.out.write(s.unwrap());
            } else {
                warn!("%s", s.unwrap_err());
            }
        }
    }
    pub fn reset(&self) {
        let mut vars = Variables::new();
        let s = do self.ti.strings.find_equiv(&("op"))
                       .map_consume_default(Err(~"can't find terminfo capability `op`")) |&op| {
                           expand(op, [], &mut vars)
                       };
        if s.is_ok() {
            self.out.write(s.unwrap());
        } else if self.num_colors > 0 {
            warn!("%s", s.unwrap_err());
        } else {
            debug!("%s", s.unwrap_err());
        }
    }

    priv fn dim_if_necessary(&self, color: color::Color) -> color::Color {
        if color >= self.num_colors && color >= 8 && color < 16 {
            color-8
        } else { color }
    }
}

#[cfg(target_os = "win32")]
impl Terminal {
    pub fn new(out: @io::Writer) -> Result<Terminal, ~str> {
        return Ok(Terminal {out: out, num_colors: 0});
    }

    pub fn fg(&self, _color: color::Color) {
    }

    pub fn bg(&self, _color: color::Color) {
    }

    pub fn reset(&self) {
    }
}
<|endoftext|>


<commit_before>// -*- coding: utf-8 -*-
// ------------------------------------------------------------------------------------------------
// Copyright © 2019, HST authors.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
// in compliance with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied.  See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------------------------------------

//! Defines a process type that includes all of the CSP language.

use std::fmt::Debug;
use std::fmt::Display;
use std::rc::Rc;

use auto_enums::enum_derive;
use auto_from::From;

use crate::internal_choice::InternalChoice;
use crate::prefix::Prefix;
use crate::primitives::Skip;
use crate::primitives::Stop;
use crate::process::Afters;
use crate::process::Initials;

/// A process type that includes all of the primitive processes and operators in the CSP language.
/// Note that you should never need to construct instances of this type directly; use the helper
/// constructor for each process (e.g. [`stop`]) or operator (TBD) instead.
///
/// [`stop`]: ../primitives/fn.stop.html
#[derive(Clone, Eq, Hash, PartialEq)]
pub struct CSP<E>(Rc<CSPSig<E, CSP<E>>>);

impl<E: Display> Display for CSP<E> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        (self.0.as_ref() as &dyn Display).fmt(f)
    }
}

impl<E: Display> Debug for CSP<E> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        (self.0.as_ref() as &dyn Debug).fmt(f)
    }
}

impl<E, T> From<T> for CSP<E>
where
    CSPSig<E, CSP<E>>: From<T>,
{
    fn from(t: T) -> CSP<E> {
        CSP(Rc::new(CSPSig::from(t)))
    }
}

impl<'a, E> Initials<'a, E> for CSP<E>
where
    CSPSig<E, CSP<E>>: Initials<'a, E>,
{
    type Initials = <CSPSig<E, CSP<E>> as Initials<'a, E>>::Initials;

    fn initials(&'a self) -> Self::Initials {
        self.0.initials()
    }
}

impl<'a, E, P> Afters<'a, E, P> for CSP<E>
where
    CSPSig<E, CSP<E>>: Afters<'a, E, P>,
{
    type Afters = <CSPSig<E, CSP<E>> as Afters<'a, E, P>>::Afters;

    fn afters(&'a self, initial: &E) -> Option<Self::Afters> {
        self.0.afters(initial)
    }
}

#[doc(hidden)]
#[enum_derive(Debug, Display)]
#[derive(Clone, Eq, From, Hash, PartialEq)]
pub enum CSPSig<E, P> {
    #[doc(hidden)]
    Stop(Stop),
    #[doc(hidden)]
    Skip(Skip),
    #[doc(hidden)]
    Prefix(Prefix<E, P>),
    #[doc(hidden)]
    InternalChoice(InternalChoice<P>),
}

#[doc(hidden)]
#[enum_derive(Iterator)]
pub enum CSPIter<Stop, Skip, Prefix, InternalChoice> {
    Stop(Stop),
    Skip(Skip),
    Prefix(Prefix),
    InternalChoice(InternalChoice),
}

impl<'a, E, P> Initials<'a, E> for CSPSig<E, P>
where
    Stop: Initials<'a, E>,
    Skip: Initials<'a, E>,
    Prefix<E, P>: Initials<'a, E>,
    InternalChoice<P>: Initials<'a, E>,
{
    type Initials = CSPIter<
        <Stop as Initials<'a, E>>::Initials,
        <Skip as Initials<'a, E>>::Initials,
        <Prefix<E, P> as Initials<'a, E>>::Initials,
        <InternalChoice<P> as Initials<'a, E>>::Initials,
    >;

    fn initials(&'a self) -> Self::Initials {
        match self {
            CSPSig::Stop(this) => CSPIter::Stop(this.initials()),
            CSPSig::Skip(this) => CSPIter::Skip(this.initials()),
            CSPSig::Prefix(this) => CSPIter::Prefix(this.initials()),
            CSPSig::InternalChoice(this) => CSPIter::InternalChoice(this.initials()),
        }
    }
}

impl<'a, E, P> Afters<'a, E, P> for CSPSig<E, P>
where
    Stop: Afters<'a, E, P>,
    Skip: Afters<'a, E, P>,
    Prefix<E, P>: Afters<'a, E, P>,
    InternalChoice<P>: Afters<'a, E, P>,
{
    type Afters = CSPIter<
        <Stop as Afters<'a, E, P>>::Afters,
        <Skip as Afters<'a, E, P>>::Afters,
        <Prefix<E, P> as Afters<'a, E, P>>::Afters,
        <InternalChoice<P> as Afters<'a, E, P>>::Afters,
    >;

    fn afters(&'a self, initial: &E) -> Option<Self::Afters> {
        match self {
            CSPSig::Stop(this) => this.afters(initial).map(CSPIter::Stop),
            CSPSig::Skip(this) => this.afters(initial).map(CSPIter::Skip),
            CSPSig::Prefix(this) => this.afters(initial).map(CSPIter::Prefix),
            CSPSig::InternalChoice(this) => this.afters(initial).map(CSPIter::InternalChoice),
        }
    }
}

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

    use proptest::arbitrary::any;
    use proptest::arbitrary::Arbitrary;
    use proptest::prop_oneof;
    use proptest::strategy::BoxedStrategy;
    use proptest::strategy::Just;
    use proptest::strategy::Strategy;

    use crate::internal_choice::internal_choice;
    use crate::prefix::prefix;
    use crate::primitives::skip;
    use crate::primitives::stop;
    use crate::primitives::tau;
    use crate::primitives::tick;
    use crate::primitives::Tau;
    use crate::primitives::Tick;

    impl<E> Arbitrary for CSP<E>
    where
        E: Arbitrary + Clone + Eq + Display + From<Tau> + From<Tick> + 'static,
        E::Strategy: Clone,
    {
        type Parameters = ();
        type Strategy = BoxedStrategy<CSP<E>>;

        fn arbitrary_with(_args: ()) -> Self::Strategy {
            let leaf = prop_oneof![Just(stop()), Just(skip())];
            let nameable_events = any::<E>()
                .prop_filter("Cannot use τ or ✔ when constructing processes", |e| {
                    *e != tau() && *e != tick()
                });
            leaf.prop_recursive(8, 256, 10, move |inner| {
                prop_oneof![
                    // We use NumberedEvent here because you shouldn't really create processes that
                    // explicitly refer to Tau and Tick; those should only be created as part of
                    // the CSP operators.
                    (nameable_events.clone(), inner.clone())
                        .prop_map(|(initial, after)| prefix(initial.into(), after)),
                    (inner.clone(), inner.clone()).prop_map(|(p, q)| internal_choice(p, q)),
                ]
            })
            .boxed()
        }
    }

}
<commit_msg>Add NameableEvents trait<commit_after>// -*- coding: utf-8 -*-
// ------------------------------------------------------------------------------------------------
// Copyright © 2019, HST authors.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
// in compliance with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied.  See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------------------------------------

//! Defines a process type that includes all of the CSP language.

use std::fmt::Debug;
use std::fmt::Display;
use std::rc::Rc;

use auto_enums::enum_derive;
use auto_from::From;

use crate::internal_choice::InternalChoice;
use crate::prefix::Prefix;
use crate::primitives::Skip;
use crate::primitives::Stop;
use crate::process::Afters;
use crate::process::Initials;

/// A process type that includes all of the primitive processes and operators in the CSP language.
/// Note that you should never need to construct instances of this type directly; use the helper
/// constructor for each process (e.g. [`stop`]) or operator (TBD) instead.
///
/// [`stop`]: ../primitives/fn.stop.html
#[derive(Clone, Eq, Hash, PartialEq)]
pub struct CSP<E>(Rc<CSPSig<E, CSP<E>>>);

impl<E: Display> Display for CSP<E> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        (self.0.as_ref() as &dyn Display).fmt(f)
    }
}

impl<E: Display> Debug for CSP<E> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        (self.0.as_ref() as &dyn Debug).fmt(f)
    }
}

impl<E, T> From<T> for CSP<E>
where
    CSPSig<E, CSP<E>>: From<T>,
{
    fn from(t: T) -> CSP<E> {
        CSP(Rc::new(CSPSig::from(t)))
    }
}

impl<'a, E> Initials<'a, E> for CSP<E>
where
    CSPSig<E, CSP<E>>: Initials<'a, E>,
{
    type Initials = <CSPSig<E, CSP<E>> as Initials<'a, E>>::Initials;

    fn initials(&'a self) -> Self::Initials {
        self.0.initials()
    }
}

impl<'a, E, P> Afters<'a, E, P> for CSP<E>
where
    CSPSig<E, CSP<E>>: Afters<'a, E, P>,
{
    type Afters = <CSPSig<E, CSP<E>> as Afters<'a, E, P>>::Afters;

    fn afters(&'a self, initial: &E) -> Option<Self::Afters> {
        self.0.afters(initial)
    }
}

#[doc(hidden)]
#[enum_derive(Debug, Display)]
#[derive(Clone, Eq, From, Hash, PartialEq)]
pub enum CSPSig<E, P> {
    #[doc(hidden)]
    Stop(Stop),
    #[doc(hidden)]
    Skip(Skip),
    #[doc(hidden)]
    Prefix(Prefix<E, P>),
    #[doc(hidden)]
    InternalChoice(InternalChoice<P>),
}

#[doc(hidden)]
#[enum_derive(Iterator)]
pub enum CSPIter<Stop, Skip, Prefix, InternalChoice> {
    Stop(Stop),
    Skip(Skip),
    Prefix(Prefix),
    InternalChoice(InternalChoice),
}

impl<'a, E, P> Initials<'a, E> for CSPSig<E, P>
where
    Stop: Initials<'a, E>,
    Skip: Initials<'a, E>,
    Prefix<E, P>: Initials<'a, E>,
    InternalChoice<P>: Initials<'a, E>,
{
    type Initials = CSPIter<
        <Stop as Initials<'a, E>>::Initials,
        <Skip as Initials<'a, E>>::Initials,
        <Prefix<E, P> as Initials<'a, E>>::Initials,
        <InternalChoice<P> as Initials<'a, E>>::Initials,
    >;

    fn initials(&'a self) -> Self::Initials {
        match self {
            CSPSig::Stop(this) => CSPIter::Stop(this.initials()),
            CSPSig::Skip(this) => CSPIter::Skip(this.initials()),
            CSPSig::Prefix(this) => CSPIter::Prefix(this.initials()),
            CSPSig::InternalChoice(this) => CSPIter::InternalChoice(this.initials()),
        }
    }
}

impl<'a, E, P> Afters<'a, E, P> for CSPSig<E, P>
where
    Stop: Afters<'a, E, P>,
    Skip: Afters<'a, E, P>,
    Prefix<E, P>: Afters<'a, E, P>,
    InternalChoice<P>: Afters<'a, E, P>,
{
    type Afters = CSPIter<
        <Stop as Afters<'a, E, P>>::Afters,
        <Skip as Afters<'a, E, P>>::Afters,
        <Prefix<E, P> as Afters<'a, E, P>>::Afters,
        <InternalChoice<P> as Afters<'a, E, P>>::Afters,
    >;

    fn afters(&'a self, initial: &E) -> Option<Self::Afters> {
        match self {
            CSPSig::Stop(this) => this.afters(initial).map(CSPIter::Stop),
            CSPSig::Skip(this) => this.afters(initial).map(CSPIter::Skip),
            CSPSig::Prefix(this) => this.afters(initial).map(CSPIter::Prefix),
            CSPSig::InternalChoice(this) => this.afters(initial).map(CSPIter::InternalChoice),
        }
    }
}

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

    use proptest::arbitrary::any;
    use proptest::arbitrary::Arbitrary;
    use proptest::prop_oneof;
    use proptest::strategy::BoxedStrategy;
    use proptest::strategy::Just;
    use proptest::strategy::MapInto;
    use proptest::strategy::Strategy;

    use crate::internal_choice::internal_choice;
    use crate::prefix::prefix;
    use crate::primitives::skip;
    use crate::primitives::stop;
    use crate::test_support::NumberedEvent;
    use crate::test_support::TestEvent;

    pub trait NameableEvents {
        type Strategy: Strategy;
        fn nameable_events() -> Self::Strategy;
    }

    impl NameableEvents for TestEvent {
        type Strategy = MapInto<<NumberedEvent as Arbitrary>::Strategy, TestEvent>;
        fn nameable_events() -> Self::Strategy {
            any::<NumberedEvent>().prop_map_into()
        }
    }

    impl<E> Arbitrary for CSP<E>
    where
        E: Clone + Debug + Display + NameableEvents + 'static,
        E::Strategy: Strategy<Value = E>,
    {
        type Parameters = ();
        type Strategy = BoxedStrategy<CSP<E>>;

        fn arbitrary_with(_args: ()) -> Self::Strategy {
            let leaf = prop_oneof![Just(stop()), Just(skip())];
            leaf.prop_recursive(8, 256, 10, move |inner| {
                prop_oneof![
                    // We use NumberedEvent here because you shouldn't really create processes that
                    // explicitly refer to Tau and Tick; those should only be created as part of
                    // the CSP operators.
                    (E::nameable_events(), inner.clone())
                        .prop_map(|(initial, after)| prefix(initial.into(), after)),
                    (inner.clone(), inner.clone()).prop_map(|(p, q)| internal_choice(p, q)),
                ]
            })
            .boxed()
        }
    }

}
<|endoftext|>


<commit_before>use runtime::Runtime;
use module::Module;
use module::ModuleResult;
use module::ModuleError;
use std::path::Path;
use std::result::Result;
use clap::ArgMatches;
use regex::Regex;

mod header;

pub struct BMModule {
    path: Option<String>,
}

const CALLNAMES : &'static [&'static str] = &[ "bm", "bookmark" ];

impl Module for BMModule {

    fn new(rt : &Runtime) -> BMModule {
        BMModule {
            path: None
        }
    }

    fn callnames() -> &'static [&'static str] {
        CALLNAMES
    }

    fn name(&self) -> &'static str{
        "Bookmark"
    }

    fn execute(&self, rt : &Runtime) -> ModuleResult {
        let cmd = rt.config.cli_matches.subcommand_matches("bm").unwrap();
        match cmd.subcommand_name() {
            Some("add")     => {
                debug!("Calling 'add'...");
                add(rt, cmd.subcommand_matches("add").unwrap())
            }
            Some("list")    => {
                debug!("Calling 'list'...");
                list(rt, cmd.subcommand_matches("list").unwrap())
            }
            Some("remove")  => {
                debug!("Calling 'remove'...");
                list(rt, cmd.subcommand_matches("remove").unwrap())
            }
            _ => {
                info!("Not calling any of add, list, remove");
                Ok(())
            }
        }
    }

    fn shutdown(&self, rt : &Runtime) -> ModuleResult {
        Ok(())
    }
}

fn add<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> ModuleResult {
    let url = sub.value_of("url").unwrap();
    let tags = get_tags(rt, sub);
    info!("Adding url '{}' with tags '{:?}'", url, tags);

    Ok(())
}

fn list<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> ModuleResult {
    let tags    = get_tags(rt, sub);
    let matcher = get_matcher(rt, sub);

    match matcher {
        Some(reg) => {
            info!("Listing urls with matcher '{}' and with tags {:?}",
                     reg.as_str(),
                     tags);
        }
        None => {
            info!("Listing urls with tags {:?}", tags);
        }
    }

    Ok(())
}

fn remove<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> ModuleResult {
    let tags    = get_tags(rt, sub);
    let matcher = get_matcher(rt, sub);
    let id      = get_id(rt, sub);

    match id {
        Some(idstr) => {
            info!("Removing urls with id '{}'", idstr);
        }
        None => {
            match matcher {
                Some(reg) => {
                    info!("Removing urls with matcher '{}' and with tags {:?}",
                             reg.as_str(), tags);
                }
                None => {
                    info!("Listing urls with tags {:?}", tags);
                }
            }
        }
    }

    Ok(())
}

fn get_tags<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Vec<String> {
    debug!("Fetching tags from commandline");
    sub.value_of("tags").and_then(|tags|
                                  Some(tags.split(",")
                                       .into_iter()
                                       .map(|s| s.to_string())
                                       .filter(|e|
                                            if e.contains(" ") {
                                                warn!("Tag contains spaces: '{}'", e);
                                                true
                                            } else {
                                                false
                                            }).collect()
                                      )
                                 ).or(Some(vec![])).unwrap()

}

fn get_matcher<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option<Regex> {
    debug!("Fetching matcher from commandline");
    if let Some(s) = sub.value_of("match") {
        if let Ok(r) = Regex::new(s) {
            return Some(r)
        } else {
            error!("Regex error, continuing without regex");
        }
    }
    None

}

fn get_id<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option<String> {
    debug!("Fetching id from commandline");
    sub.value_of("id").and_then(|s| Some(String::from(s)))
}

<commit_msg>Fixed inverted logic in get_tags()<commit_after>use runtime::Runtime;
use module::Module;
use module::ModuleResult;
use module::ModuleError;
use std::path::Path;
use std::result::Result;
use clap::ArgMatches;
use regex::Regex;

mod header;

pub struct BMModule {
    path: Option<String>,
}

const CALLNAMES : &'static [&'static str] = &[ "bm", "bookmark" ];

impl Module for BMModule {

    fn new(rt : &Runtime) -> BMModule {
        BMModule {
            path: None
        }
    }

    fn callnames() -> &'static [&'static str] {
        CALLNAMES
    }

    fn name(&self) -> &'static str{
        "Bookmark"
    }

    fn execute(&self, rt : &Runtime) -> ModuleResult {
        let cmd = rt.config.cli_matches.subcommand_matches("bm").unwrap();
        match cmd.subcommand_name() {
            Some("add")     => {
                debug!("Calling 'add'...");
                add(rt, cmd.subcommand_matches("add").unwrap())
            }
            Some("list")    => {
                debug!("Calling 'list'...");
                list(rt, cmd.subcommand_matches("list").unwrap())
            }
            Some("remove")  => {
                debug!("Calling 'remove'...");
                list(rt, cmd.subcommand_matches("remove").unwrap())
            }
            _ => {
                info!("Not calling any of add, list, remove");
                Ok(())
            }
        }
    }

    fn shutdown(&self, rt : &Runtime) -> ModuleResult {
        Ok(())
    }
}

fn add<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> ModuleResult {
    let url = sub.value_of("url").unwrap();
    let tags = get_tags(rt, sub);
    info!("Adding url '{}' with tags '{:?}'", url, tags);

    Ok(())
}

fn list<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> ModuleResult {
    let tags    = get_tags(rt, sub);
    let matcher = get_matcher(rt, sub);

    match matcher {
        Some(reg) => {
            info!("Listing urls with matcher '{}' and with tags {:?}",
                     reg.as_str(),
                     tags);
        }
        None => {
            info!("Listing urls with tags {:?}", tags);
        }
    }

    Ok(())
}

fn remove<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> ModuleResult {
    let tags    = get_tags(rt, sub);
    let matcher = get_matcher(rt, sub);
    let id      = get_id(rt, sub);

    match id {
        Some(idstr) => {
            info!("Removing urls with id '{}'", idstr);
        }
        None => {
            match matcher {
                Some(reg) => {
                    info!("Removing urls with matcher '{}' and with tags {:?}",
                             reg.as_str(), tags);
                }
                None => {
                    info!("Listing urls with tags {:?}", tags);
                }
            }
        }
    }

    Ok(())
}

fn get_tags<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Vec<String> {
    debug!("Fetching tags from commandline");
    sub.value_of("tags").and_then(|tags|
                                  Some(tags.split(",")
                                       .into_iter()
                                       .map(|s| s.to_string())
                                       .filter(|e|
                                            if e.contains(" ") {
                                                warn!("Tag contains spaces: '{}'", e);
                                                false
                                            } else {
                                                true
                                            }).collect()
                                      )
                                 ).or(Some(vec![])).unwrap()

}

fn get_matcher<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option<Regex> {
    debug!("Fetching matcher from commandline");
    if let Some(s) = sub.value_of("match") {
        if let Ok(r) = Regex::new(s) {
            return Some(r)
        } else {
            error!("Regex error, continuing without regex");
        }
    }
    None

}

fn get_id<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option<String> {
    debug!("Fetching id from commandline");
    sub.value_of("id").and_then(|s| Some(String::from(s)))
}

<|endoftext|>


<commit_before>use super::{guards::*, sqlite::DbConn, tantivy::SearchEngine, util};
use crate::{
    adapters::{self, json, user_communication},
    core::{
        prelude::*,
        usecases::{self, DuplicateType},
        util::geo,
    },
    infrastructure::error::AppError,
};

use csv;
use rocket::{
    self,
    http::{ContentType, Cookie, Cookies, Status},
    request::Form,
    response::{content::Content, Responder, Response},
    Route,
};
use rocket_contrib::json::Json;
use std::result;

mod count;
mod events;
pub mod geocoding;
mod ratings;
mod search;
#[cfg(test)]
pub mod tests;
mod users;

type Result<T> = result::Result<Json<T>, AppError>;

pub fn routes() -> Vec<Route> {
    routes![
        login,
        logout,
        confirm_email_address,
        subscribe_to_bbox,
        get_bbox_subscriptions,
        unsubscribe_all_bboxes,
        get_entry,
        post_entry,
        put_entry,
        events::post_event,
        events::post_event_with_token,
        events::get_event,
        events::get_events,
        events::get_events_with_token,
        events::put_event,
        events::put_event_with_token,
        events::delete_event,
        events::delete_event_with_token,
        users::post_user,
        ratings::post_rating,
        ratings::get_rating,
        users::get_user,
        users::delete_user,
        get_categories,
        get_category,
        get_tags,
        search::get_search,
        get_duplicates,
        count::get_count_entries,
        count::get_count_tags,
        get_version,
        csv_export,
        get_api
    ]
}

#[derive(Deserialize, Debug, Clone)]
struct UserId {
    u_id: String,
}

#[get("/entries/<ids>")]
fn get_entry(db: DbConn, ids: String) -> Result<Vec<json::Entry>> {
    // TODO: Only lookup and return a single entity
    // TODO: Add a new method for searching multiple ids
    let ids = util::extract_ids(&ids);
    let entries = usecases::get_entries(&*db, &ids)?;
    let ratings = usecases::get_ratings_by_entry_ids(&*db, &ids)?;
    Ok(Json(
        entries
            .into_iter()
            .map(|e| {
                let r = ratings.get(&e.id).cloned().unwrap_or_else(|| vec![]);
                json::Entry::from_entry_with_ratings(e, r)
            })
            .collect::<Vec<json::Entry>>(),
    ))
}

#[get("/duplicates")]
fn get_duplicates(db: DbConn) -> Result<Vec<(String, String, DuplicateType)>> {
    let entries = db.all_entries()?;
    let ids = usecases::find_duplicates(&entries);
    Ok(Json(ids))
}

#[get("/server/version")]
fn get_version() -> &'static str {
    env!("CARGO_PKG_VERSION")
}

#[get("/server/api.yaml")]
fn get_api() -> Content<&'static str> {
    let data = include_str!("../../../../openapi.yaml");
    let c_type = ContentType::new("text", "yaml");
    Content(c_type, data)
}

#[post("/login", format = "application/json", data = "<login>")]
fn login(mut db: DbConn, mut cookies: Cookies, login: Json<usecases::Login>) -> Result<()> {
    let username = usecases::login(&mut *db, &login.into_inner())?;
    cookies.add_private(
        Cookie::build(COOKIE_USER_KEY, username)
            .same_site(rocket::http::SameSite::None)
            .finish(),
    );
    Ok(Json(()))
}

#[post("/logout", format = "application/json")]
fn logout(mut cookies: Cookies) -> Result<()> {
    cookies.remove_private(Cookie::named(COOKIE_USER_KEY));
    Ok(Json(()))
}

#[post("/confirm-email-address", format = "application/json", data = "<user>")]
fn confirm_email_address(mut db: DbConn, user: Json<UserId>) -> Result<()> {
    let u_id = user.into_inner().u_id;
    usecases::confirm_email_address(&mut *db, &u_id)?;
    Ok(Json(()))
}

#[post(
    "/subscribe-to-bbox",
    format = "application/json",
    data = "<coordinates>"
)]
fn subscribe_to_bbox(
    mut db: DbConn,
    user: Login,
    coordinates: Json<Vec<json::Coordinate>>,
) -> Result<()> {
    let coordinates: Vec<Coordinate> = coordinates
        .into_inner()
        .into_iter()
        .map(Coordinate::from)
        .collect();
    let Login(username) = user;
    usecases::subscribe_to_bbox(&coordinates, &username, &mut *db)?;
    Ok(Json(()))
}

#[delete("/unsubscribe-all-bboxes")]
fn unsubscribe_all_bboxes(mut db: DbConn, user: Login) -> Result<()> {
    let Login(username) = user;
    usecases::unsubscribe_all_bboxes_by_username(&mut *db, &username)?;
    Ok(Json(()))
}

#[get("/bbox-subscriptions")]
fn get_bbox_subscriptions(db: DbConn, user: Login) -> Result<Vec<json::BboxSubscription>> {
    let Login(username) = user;
    let user_subscriptions = usecases::get_bbox_subscriptions(&username, &*db)?
        .into_iter()
        .map(|s| json::BboxSubscription {
            id: s.id,
            south_west_lat: s.bbox.south_west.lat,
            south_west_lng: s.bbox.south_west.lng,
            north_east_lat: s.bbox.north_east.lat,
            north_east_lng: s.bbox.north_east.lng,
        })
        .collect();
    Ok(Json(user_subscriptions))
}

#[post("/entries", format = "application/json", data = "<e>")]
fn post_entry(
    mut db: DbConn,
    mut search_engine: SearchEngine,
    e: Json<usecases::NewEntry>,
) -> Result<String> {
    let e = e.into_inner();
    let id = usecases::create_new_entry(&mut *db, Some(&mut search_engine), e.clone())?;
    let email_addresses = usecases::email_addresses_by_coordinate(&mut *db, &e.lat, &e.lng)?;
    let all_categories = db.all_categories()?;
    util::notify_create_entry(&email_addresses, &e, &id, all_categories);
    Ok(Json(id))
}

#[put("/entries/<id>", format = "application/json", data = "<e>")]
fn put_entry(
    mut db: DbConn,
    mut search_engine: SearchEngine,
    id: String,
    e: Json<usecases::UpdateEntry>,
) -> Result<String> {
    let e = e.into_inner();
    usecases::update_entry(&mut *db, Some(&mut search_engine), e.clone())?;
    let email_addresses = usecases::email_addresses_by_coordinate(&mut *db, &e.lat, &e.lng)?;
    let all_categories = db.all_categories()?;
    util::notify_update_entry(&email_addresses, &e, all_categories);
    Ok(Json(id))
}

#[get("/tags")]
fn get_tags(db: DbConn) -> Result<Vec<String>> {
    Ok(Json(db.all_tags()?.into_iter().map(|t| t.id).collect()))
}

#[get("/categories")]
fn get_categories(db: DbConn) -> Result<Vec<Category>> {
    let categories = db.all_categories()?;
    Ok(Json(categories))
}

#[get("/categories/<ids>")]
fn get_category(db: DbConn, ids: String) -> Result<Vec<Category>> {
    // TODO: Only lookup and return a single entity
    // TODO: Add a new method for searching multiple ids
    let ids = util::extract_ids(&ids);
    let categories = db
        .all_categories()?
        .into_iter()
        .filter(|c| ids.iter().any(|id| &c.id == id))
        .collect::<Vec<Category>>();
    Ok(Json(categories))
}

#[derive(FromForm, Clone, Serialize)]
struct CsvExport {
    bbox: String,
}

#[get("/export/entries.csv?<export..>")]
fn csv_export<'a>(
    db: DbConn,
    export: Form<CsvExport>,
) -> result::Result<Content<String>, AppError> {
    let bbox = export
        .bbox
        .parse::<geo::MapBbox>()
        .map_err(|_| ParameterError::Bbox)
        .map_err(Error::Parameter)
        .map_err(AppError::Business)?;

    let entries: Vec<_> = db.get_entries_by_bbox(&bbox)?;
    let all_categories: Vec<_> = db.all_categories()?;
    let avg_ratings = match super::ENTRY_RATINGS.lock() {
        Ok(guard) => guard,
        Err(poisoned) => poisoned.into_inner(),
    };

    let entries_categories_and_ratings = entries
        .into_iter()
        .map(|e| {
            let categories = all_categories
                .iter()
                .filter(|c1| e.categories.iter().any(|c2| *c2 == c1.id))
                .cloned()
                .collect::<Vec<Category>>();
            let avg_rating = *avg_ratings.get(&e.id).unwrap_or_else(|| &0.0);
            (e, categories, avg_rating)
        })
        .collect::<Vec<_>>();

    let records: Vec<adapters::csv::CsvRecord> = entries_categories_and_ratings
        .into_iter()
        .map(adapters::csv::CsvRecord::from)
        .collect();

    let buff: Vec<u8> = vec![];
    let mut wtr = csv::Writer::from_writer(buff);

    for r in records {
        wtr.serialize(r)?;
    }
    wtr.flush()?;
    let data = String::from_utf8(wtr.into_inner()?)?;

    Ok(Content(ContentType::CSV, data))
}

impl<'r> Responder<'r> for AppError {
    fn respond_to(self, _: &rocket::Request) -> result::Result<Response<'r>, Status> {
        if let AppError::Business(ref err) = self {
            match *err {
                Error::Parameter(ref err) => {
                    return Err(match *err {
                        ParameterError::Credentials | ParameterError::Unauthorized => {
                            Status::Unauthorized
                        }
                        ParameterError::UserExists => <Status>::new(400, "UserExists"),
                        ParameterError::EmailNotConfirmed => {
                            <Status>::new(403, "EmailNotConfirmed")
                        }
                        ParameterError::Forbidden | ParameterError::OwnedTag => Status::Forbidden,
                        _ => Status::BadRequest,
                    });
                }
                Error::Repo(ref err) => {
                    if let RepoError::NotFound = *err {
                        return Err(Status::NotFound);
                    }
                }
                _ => {}
            }
        }
        error!("Error: {}", self);
        Err(Status::InternalServerError)
    }
}
<commit_msg>Add TODO for restricting CSV export<commit_after>use super::{guards::*, sqlite::DbConn, tantivy::SearchEngine, util};
use crate::{
    adapters::{self, json, user_communication},
    core::{
        prelude::*,
        usecases::{self, DuplicateType},
        util::geo,
    },
    infrastructure::error::AppError,
};

use csv;
use rocket::{
    self,
    http::{ContentType, Cookie, Cookies, Status},
    request::Form,
    response::{content::Content, Responder, Response},
    Route,
};
use rocket_contrib::json::Json;
use std::result;

mod count;
mod events;
pub mod geocoding;
mod ratings;
mod search;
#[cfg(test)]
pub mod tests;
mod users;

type Result<T> = result::Result<Json<T>, AppError>;

pub fn routes() -> Vec<Route> {
    routes![
        login,
        logout,
        confirm_email_address,
        subscribe_to_bbox,
        get_bbox_subscriptions,
        unsubscribe_all_bboxes,
        get_entry,
        post_entry,
        put_entry,
        events::post_event,
        events::post_event_with_token,
        events::get_event,
        events::get_events,
        events::get_events_with_token,
        events::put_event,
        events::put_event_with_token,
        events::delete_event,
        events::delete_event_with_token,
        users::post_user,
        ratings::post_rating,
        ratings::get_rating,
        users::get_user,
        users::delete_user,
        get_categories,
        get_category,
        get_tags,
        search::get_search,
        get_duplicates,
        count::get_count_entries,
        count::get_count_tags,
        get_version,
        csv_export,
        get_api
    ]
}

#[derive(Deserialize, Debug, Clone)]
struct UserId {
    u_id: String,
}

#[get("/entries/<ids>")]
fn get_entry(db: DbConn, ids: String) -> Result<Vec<json::Entry>> {
    // TODO: Only lookup and return a single entity
    // TODO: Add a new method for searching multiple ids
    let ids = util::extract_ids(&ids);
    let entries = usecases::get_entries(&*db, &ids)?;
    let ratings = usecases::get_ratings_by_entry_ids(&*db, &ids)?;
    Ok(Json(
        entries
            .into_iter()
            .map(|e| {
                let r = ratings.get(&e.id).cloned().unwrap_or_else(|| vec![]);
                json::Entry::from_entry_with_ratings(e, r)
            })
            .collect::<Vec<json::Entry>>(),
    ))
}

#[get("/duplicates")]
fn get_duplicates(db: DbConn) -> Result<Vec<(String, String, DuplicateType)>> {
    let entries = db.all_entries()?;
    let ids = usecases::find_duplicates(&entries);
    Ok(Json(ids))
}

#[get("/server/version")]
fn get_version() -> &'static str {
    env!("CARGO_PKG_VERSION")
}

#[get("/server/api.yaml")]
fn get_api() -> Content<&'static str> {
    let data = include_str!("../../../../openapi.yaml");
    let c_type = ContentType::new("text", "yaml");
    Content(c_type, data)
}

#[post("/login", format = "application/json", data = "<login>")]
fn login(mut db: DbConn, mut cookies: Cookies, login: Json<usecases::Login>) -> Result<()> {
    let username = usecases::login(&mut *db, &login.into_inner())?;
    cookies.add_private(
        Cookie::build(COOKIE_USER_KEY, username)
            .same_site(rocket::http::SameSite::None)
            .finish(),
    );
    Ok(Json(()))
}

#[post("/logout", format = "application/json")]
fn logout(mut cookies: Cookies) -> Result<()> {
    cookies.remove_private(Cookie::named(COOKIE_USER_KEY));
    Ok(Json(()))
}

#[post("/confirm-email-address", format = "application/json", data = "<user>")]
fn confirm_email_address(mut db: DbConn, user: Json<UserId>) -> Result<()> {
    let u_id = user.into_inner().u_id;
    usecases::confirm_email_address(&mut *db, &u_id)?;
    Ok(Json(()))
}

#[post(
    "/subscribe-to-bbox",
    format = "application/json",
    data = "<coordinates>"
)]
fn subscribe_to_bbox(
    mut db: DbConn,
    user: Login,
    coordinates: Json<Vec<json::Coordinate>>,
) -> Result<()> {
    let coordinates: Vec<Coordinate> = coordinates
        .into_inner()
        .into_iter()
        .map(Coordinate::from)
        .collect();
    let Login(username) = user;
    usecases::subscribe_to_bbox(&coordinates, &username, &mut *db)?;
    Ok(Json(()))
}

#[delete("/unsubscribe-all-bboxes")]
fn unsubscribe_all_bboxes(mut db: DbConn, user: Login) -> Result<()> {
    let Login(username) = user;
    usecases::unsubscribe_all_bboxes_by_username(&mut *db, &username)?;
    Ok(Json(()))
}

#[get("/bbox-subscriptions")]
fn get_bbox_subscriptions(db: DbConn, user: Login) -> Result<Vec<json::BboxSubscription>> {
    let Login(username) = user;
    let user_subscriptions = usecases::get_bbox_subscriptions(&username, &*db)?
        .into_iter()
        .map(|s| json::BboxSubscription {
            id: s.id,
            south_west_lat: s.bbox.south_west.lat,
            south_west_lng: s.bbox.south_west.lng,
            north_east_lat: s.bbox.north_east.lat,
            north_east_lng: s.bbox.north_east.lng,
        })
        .collect();
    Ok(Json(user_subscriptions))
}

#[post("/entries", format = "application/json", data = "<e>")]
fn post_entry(
    mut db: DbConn,
    mut search_engine: SearchEngine,
    e: Json<usecases::NewEntry>,
) -> Result<String> {
    let e = e.into_inner();
    let id = usecases::create_new_entry(&mut *db, Some(&mut search_engine), e.clone())?;
    let email_addresses = usecases::email_addresses_by_coordinate(&mut *db, &e.lat, &e.lng)?;
    let all_categories = db.all_categories()?;
    util::notify_create_entry(&email_addresses, &e, &id, all_categories);
    Ok(Json(id))
}

#[put("/entries/<id>", format = "application/json", data = "<e>")]
fn put_entry(
    mut db: DbConn,
    mut search_engine: SearchEngine,
    id: String,
    e: Json<usecases::UpdateEntry>,
) -> Result<String> {
    let e = e.into_inner();
    usecases::update_entry(&mut *db, Some(&mut search_engine), e.clone())?;
    let email_addresses = usecases::email_addresses_by_coordinate(&mut *db, &e.lat, &e.lng)?;
    let all_categories = db.all_categories()?;
    util::notify_update_entry(&email_addresses, &e, all_categories);
    Ok(Json(id))
}

#[get("/tags")]
fn get_tags(db: DbConn) -> Result<Vec<String>> {
    Ok(Json(db.all_tags()?.into_iter().map(|t| t.id).collect()))
}

#[get("/categories")]
fn get_categories(db: DbConn) -> Result<Vec<Category>> {
    let categories = db.all_categories()?;
    Ok(Json(categories))
}

#[get("/categories/<ids>")]
fn get_category(db: DbConn, ids: String) -> Result<Vec<Category>> {
    // TODO: Only lookup and return a single entity
    // TODO: Add a new method for searching multiple ids
    let ids = util::extract_ids(&ids);
    let categories = db
        .all_categories()?
        .into_iter()
        .filter(|c| ids.iter().any(|id| &c.id == id))
        .collect::<Vec<Category>>();
    Ok(Json(categories))
}

#[derive(FromForm, Clone, Serialize)]
struct CsvExport {
    bbox: String,
}

// TODO: CSV export should only be permitted with a valid API key!
// https://github.com/slowtec/openfairdb/issues/147
#[get("/export/entries.csv?<export..>")]
fn csv_export<'a>(
    db: DbConn,
    export: Form<CsvExport>,
) -> result::Result<Content<String>, AppError> {
    let bbox = export
        .bbox
        .parse::<geo::MapBbox>()
        .map_err(|_| ParameterError::Bbox)
        .map_err(Error::Parameter)
        .map_err(AppError::Business)?;

    let entries: Vec<_> = db.get_entries_by_bbox(&bbox)?;
    let all_categories: Vec<_> = db.all_categories()?;
    let avg_ratings = match super::ENTRY_RATINGS.lock() {
        Ok(guard) => guard,
        Err(poisoned) => poisoned.into_inner(),
    };

    let entries_categories_and_ratings = entries
        .into_iter()
        .map(|e| {
            let categories = all_categories
                .iter()
                .filter(|c1| e.categories.iter().any(|c2| *c2 == c1.id))
                .cloned()
                .collect::<Vec<Category>>();
            let avg_rating = *avg_ratings.get(&e.id).unwrap_or_else(|| &0.0);
            (e, categories, avg_rating)
        })
        .collect::<Vec<_>>();

    let records: Vec<adapters::csv::CsvRecord> = entries_categories_and_ratings
        .into_iter()
        .map(adapters::csv::CsvRecord::from)
        .collect();

    let buff: Vec<u8> = vec![];
    let mut wtr = csv::Writer::from_writer(buff);

    for r in records {
        wtr.serialize(r)?;
    }
    wtr.flush()?;
    let data = String::from_utf8(wtr.into_inner()?)?;

    Ok(Content(ContentType::CSV, data))
}

impl<'r> Responder<'r> for AppError {
    fn respond_to(self, _: &rocket::Request) -> result::Result<Response<'r>, Status> {
        if let AppError::Business(ref err) = self {
            match *err {
                Error::Parameter(ref err) => {
                    return Err(match *err {
                        ParameterError::Credentials | ParameterError::Unauthorized => {
                            Status::Unauthorized
                        }
                        ParameterError::UserExists => <Status>::new(400, "UserExists"),
                        ParameterError::EmailNotConfirmed => {
                            <Status>::new(403, "EmailNotConfirmed")
                        }
                        ParameterError::Forbidden | ParameterError::OwnedTag => Status::Forbidden,
                        _ => Status::BadRequest,
                    });
                }
                Error::Repo(ref err) => {
                    if let RepoError::NotFound = *err {
                        return Err(Status::NotFound);
                    }
                }
                _ => {}
            }
        }
        error!("Error: {}", self);
        Err(Status::InternalServerError)
    }
}
<|endoftext|>


<commit_before>extern crate unicode_names;

use irc::client::prelude::*;
use irc::error::Error as IrcError;

use plugin::*;

#[derive(PluginName, Debug)]
pub struct Emoji;
impl Emoji {
    pub fn new() -> Emoji {
        Emoji {}
    }

    fn emoji(&self, server: &IrcServer, content: &str, target: &str) -> Result<(), IrcError> {

        let mut names: Vec<String> = Vec::new();
        for emoji in self.return_emojis(content) {

            let name = match unicode_names::name(emoji) {
                Some(v) => format!("{}", v).to_lowercase(),
                None => "UNKNOWN".to_string(),
            };

            names.push(name);
        }

        server.send_privmsg(target, &names.join(", "))
    }

    fn return_emojis(&self, string: &str) -> Vec<char> {

        let mut emojis: Vec<char> = Vec::new();

        for c in string.chars() {
            if self.is_emoji(&c) {
                emojis.push(c);
            }
        }

        emojis
    }

    fn is_emoji(&self, c: &char) -> bool {
        // Emoji ranges from stackoverflow:
        // https://stackoverflow.com/questions/30757193/find-out-if-character-in-string-is-emoji
        match *c { '\u{1F600}'...'\u{1F64F}'     // Emoticons
            | '\u{1F300}'...'\u{1F5FF}'          // Misc Symbols and Pictographs
            | '\u{1F680}'...'\u{1F6FF}'          // Transport and Map
            | '\u{2600}' ...'\u{26FF}'           // Misc symbols
            | '\u{2700}' ...'\u{27BF}'           // Dingbats
            | '\u{FE00}' ...'\u{FE0F}'           // Variation Selectors
            | '\u{1F900}'...'\u{1F9FF}'          // Supplemental Symbols and Pictographs
            | '\u{20D0}' ...'\u{20FF}' => true,  // Combining Diacritical Marks for Symbols
            _ => false,
        }
    }
}

impl Plugin for Emoji {
    fn is_allowed(&self, _: &IrcServer, message: &Message) -> bool {
        match message.command {
            Command::PRIVMSG(_, _) => true,
            _ => false,
        }
    }

    fn execute(&mut self, server: &IrcServer, message: &Message) -> Result<(), IrcError> {
        match message.command {
            Command::PRIVMSG(_, ref content) => {
                self.emoji(server, content, message.response_target().unwrap())
            }
            _ => Ok(()),
        }
    }

    fn command(&mut self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> {
        server.send_notice(&command.source,
                           "This Plugin does not implement any commands.")
    }
}

#[cfg(test)]
mod tests {}
<commit_msg>Add emoji counting<commit_after>extern crate unicode_names;

use std::fmt;

use irc::client::prelude::*;
use irc::error::Error as IrcError;

use plugin::*;

struct EmojiHandle {
    symbol: char,
    count: i32,
}

impl fmt::Display for EmojiHandle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        let name = match unicode_names::name(self.symbol) {
            Some(sym) => sym.to_string().to_lowercase(),
            None => String::from("UNKNOWN"),
        };

        if self.count > 1 {
            write!(f, "{}x {}", self.count, name)
        } else {
            write!(f, "{}", name)
        }
    }
}

#[derive(PluginName, Debug)]
pub struct Emoji;

impl Emoji {
    pub fn new() -> Emoji {
        Emoji {}
    }

    fn emoji(&self, server: &IrcServer, content: &str, target: &str) -> Result<(), IrcError> {
        let names = self.return_emojis(content)
            .iter()
            .map(|e| e.to_string())
            .collect::<Vec<String>>();

        server.send_privmsg(target, &names.join(", "))
    }

    fn return_emojis(&self, string: &str) -> Vec<EmojiHandle> {

        let mut emojis: Vec<EmojiHandle> = Vec::new();

        let mut current = EmojiHandle {
            symbol: ' ',
            count: 0,
        };

        for c in string.chars() {
            if self.is_emoji(&c) {
                if current.symbol == c {
                    current.count = current.count + 1;

                } else {
                    if current.count > 0 {
                        emojis.push(current);
                    }

                    current = EmojiHandle {
                        symbol: c,
                        count: 1,
                    }
                }
            }
        }

        if current.count > 0 {
            emojis.push(current);
        }

        emojis
    }

    fn is_emoji(&self, c: &char) -> bool {
        // Emoji ranges from stackoverflow:
        // https://stackoverflow.com/questions/30757193/find-out-if-character-in-string-is-emoji
        match *c { '\u{1F600}'...'\u{1F64F}'     // Emoticons
            | '\u{1F300}'...'\u{1F5FF}'          // Misc Symbols and Pictographs
            | '\u{1F680}'...'\u{1F6FF}'          // Transport and Map
            | '\u{2600}' ...'\u{26FF}'           // Misc symbols
            | '\u{2700}' ...'\u{27BF}'           // Dingbats
            | '\u{FE00}' ...'\u{FE0F}'           // Variation Selectors
            | '\u{1F900}'...'\u{1F9FF}'          // Supplemental Symbols and Pictographs
            | '\u{20D0}' ...'\u{20FF}' => true,  // Combining Diacritical Marks for Symbols
            _ => false,
        }
    }
}

impl Plugin for Emoji {
    fn is_allowed(&self, _: &IrcServer, message: &Message) -> bool {
        match message.command {
            Command::PRIVMSG(_, _) => true,
            _ => false,
        }
    }

    fn execute(&mut self, server: &IrcServer, message: &Message) -> Result<(), IrcError> {
        match message.command {
            Command::PRIVMSG(_, ref content) => {
                self.emoji(server, content, message.response_target().unwrap())
            }
            _ => Ok(()),
        }
    }

    fn command(&mut self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> {
        server.send_notice(&command.source,
                           "This Plugin does not implement any commands.")
    }
}

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


<commit_before>use platform::time::time_now;
use storage::CacheError;

use super::cmd::Resp;

pub fn bytes_to_u64(bytes: &Vec<u8>) -> Option<u64> {
    match String::from_utf8(bytes.clone()) {
        Ok(st) => {
            match st.parse::<u64>() {
                Ok(num) => Some(num),
                Err(_) => None,
            }
        }
        Err(_) => None,
    }
}

pub fn u64_to_bytes(num: &u64) -> Vec<u8> {
    let arr = num.to_string().into_bytes();

    let mut bytes = vec![];
    bytes.extend(arr);
    bytes
}

pub fn convert_exptime(exptime: u32) -> Option<f64> {
    // If exptime is greater than zero it means it's set, otherwise unset
    if exptime > 0 {
        let tm;

        // Is it an interval greater than 30 days? Then it's a timestamp
        if exptime > 60 * 60 * 24 * 30 {
            tm = exptime as f64;

        } else {
            // Otherwise it's relative from now
            tm = time_now() + exptime as f64;
        }

        return Some(tm);
    }

    None
}

pub fn from_cache_err(err: &CacheError) -> Resp {
    match *err {
        CacheError::KeyTooLong => {
            Resp::ClientError("bad command line format".to_string())
        }
        CacheError::ValueTooLong => {
            Resp::ServerError("object too large for cache".to_string())
        }
        _ => Resp::Error,
    }
}

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

    #[test]
    fn test_bytes_to_u64() {
        // whitespace
        assert_eq!(None, bytes_to_u64(&vec![b' ', b'2']));

        // alpha
        assert_eq!(None, bytes_to_u64(&vec![b'0', b'x', b'2']));

        // negative
        assert_eq!(None, bytes_to_u64(&vec![b'-', b'2']));

        // too long for u64
        assert_eq!(None, bytes_to_u64(&vec![b'1'; 255]));

        // ok
        assert_eq!(12, bytes_to_u64(&vec![b'1', b'2']).unwrap());
    }

    #[test]
    fn test_u64_to_bytes() {
        // any u64 is representable as bytes so there are no boundary conditions to
        // check
        assert_eq!(vec![b'1', b'2'], u64_to_bytes(&12));
    }
}
<commit_msg>add test for convert_exptime<commit_after>use platform::time::time_now;
use storage::CacheError;

use super::cmd::Resp;

pub fn bytes_to_u64(bytes: &Vec<u8>) -> Option<u64> {
    match String::from_utf8(bytes.clone()) {
        Ok(st) => {
            match st.parse::<u64>() {
                Ok(num) => Some(num),
                Err(_) => None,
            }
        }
        Err(_) => None,
    }
}

pub fn u64_to_bytes(num: &u64) -> Vec<u8> {
    let arr = num.to_string().into_bytes();

    let mut bytes = vec![];
    bytes.extend(arr);
    bytes
}

pub fn convert_exptime(exptime: u32) -> Option<f64> {
    // If exptime is greater than zero it means it's set, otherwise unset
    if exptime > 0 {
        let tm;

        // Is it an interval greater than 30 days? Then it's a timestamp
        if exptime > 60 * 60 * 24 * 30 {
            tm = exptime as f64;

        } else {
            // Otherwise it's relative from now
            tm = time_now() + exptime as f64;
        }

        return Some(tm);
    }

    None
}

pub fn from_cache_err(err: &CacheError) -> Resp {
    match *err {
        CacheError::KeyTooLong => {
            Resp::ClientError("bad command line format".to_string())
        }
        CacheError::ValueTooLong => {
            Resp::ServerError("object too large for cache".to_string())
        }
        _ => Resp::Error,
    }
}

#[cfg(test)]
mod tests {
    use platform::time::time_now;
    use testlib::cmp::eq_f64;

    use super::bytes_to_u64;
    use super::convert_exptime;
    use super::u64_to_bytes;

    #[test]
    fn test_bytes_to_u64() {
        // whitespace
        assert_eq!(None, bytes_to_u64(&vec![b' ', b'2']));

        // alpha
        assert_eq!(None, bytes_to_u64(&vec![b'0', b'x', b'2']));

        // negative
        assert_eq!(None, bytes_to_u64(&vec![b'-', b'2']));

        // too long for u64
        assert_eq!(None, bytes_to_u64(&vec![b'1'; 255]));

        // ok
        assert_eq!(12, bytes_to_u64(&vec![b'1', b'2']).unwrap());
    }

    #[test]
    fn test_u64_to_bytes() {
        // any u64 is representable as bytes so there are no boundary conditions to
        // check
        assert_eq!(vec![b'1', b'2'], u64_to_bytes(&12));
    }

    #[test]
    fn test_convert_exptime() {
        assert_eq!(None, convert_exptime(0));

        // big enough to be a timestamp
        let val = (60 * 60 * 24 * 30) + 1;
        assert_eq!(Some(val as f64), convert_exptime(val));

        // not big enough to be a timestamp - it's a relative time
        let val = 5;
        let expected = time_now() + val as f64;
        let actual = convert_exptime(val).unwrap();
        assert!(eq_f64(expected, actual, 0.01));
    }
}
<|endoftext|>