<commit_before>//! A general purpose `Batcher` implementation based on radix sort.

use timely::progress::frontier::Antichain;

use ::difference::Monoid;

use lattice::Lattice;
use trace::{Batch, Batcher, Builder};

/// Creates batches from unordered tuples.
pub struct MergeBatcher<K: Ord, V: Ord, T: Ord, R: Monoid, B: Batch<K, V, T, R>> {
    sorter: MergeSorter<(K, V), T, R>,
    lower: Vec<T>,
    frontier: Antichain<T>,
    phantom: ::std::marker::PhantomData<B>,
}

impl<K, V, T, R, B> Batcher<K, V, T, R, B> for MergeBatcher<K, V, T, R, B>
where
    K: Ord+Clone,
    V: Ord+Clone,
    T: Lattice+Ord+Clone,
    R: Monoid,
    B: Batch<K, V, T, R>,
{
    fn new() -> Self {
        MergeBatcher {
            sorter: MergeSorter::new(),
            frontier: Antichain::new(),
            lower: vec![T::minimum()],
            phantom: ::std::marker::PhantomData,
        }
    }

    #[inline(never)]
    fn push_batch(&mut self, batch: &mut Vec<((K,V),T,R)>) {
        self.sorter.push(batch);
    }

    // Sealing a batch means finding those updates with times not greater or equal to any time
    // in `upper`. All updates must have time greater or equal to the previously used `upper`,
    // which we call `lower`, by assumption that after sealing a batcher we receive no more
    // updates with times not greater or equal to `upper`.
    #[inline(never)]
    fn seal(&mut self, upper: &[T]) -> B {

        let mut builder = B::Builder::new();

        let mut merged = Vec::new();
        self.sorter.finish_into(&mut merged);

        let mut kept = Vec::new();
        let mut keep = Vec::new();

        self.frontier.clear();

        // TODO: Re-use buffer, rather than dropping.
        for mut buffer in merged.drain(..) {
            for ((key, val), time, diff) in buffer.drain(..) {
                if upper.iter().any(|t| t.less_equal(&time)) {
                    // keep_count += 1;
                    self.frontier.insert(time.clone());
                    if keep.len() == keep.capacity() {
                        if keep.len() > 0 {
                            kept.push(keep);
                            keep = self.sorter.empty();
                        }
                    }
                    keep.push(((key, val), time, diff));
                }
                else {
                    // seal_count += 1;
                    builder.push((key, val, time, diff));
                }
            }
            // Recycling buffer.
            self.sorter.push(&mut buffer);
        }

        // Finish the kept data.
        if keep.len() > 0 {
            kept.push(keep);
        }
        if kept.len() > 0 {
            self.sorter.push_list(kept);
        }

        // Drain buffers (fast reclaimation).
        // TODO : This isn't obviously the best policy, but "safe" wrt footprint.
        //        In particular, if we are reading serialized input data, we may
        //        prefer to keep these buffers around to re-fill, if possible.
        let mut buffer = Vec::new();
        self.sorter.push(&mut buffer);
        while buffer.capacity() > 0 {
            buffer = Vec::new();
            self.sorter.push(&mut buffer);
        }

        let seal = builder.done(&self.lower[..], &upper[..], &self.lower[..]);
        self.lower = upper.to_vec();
        seal
    }

    // the frontier of elements remaining after the most recent call to `self.seal`.
    fn frontier(&mut self) -> &[T] {
        self.frontier.elements()
    }
}

use std::slice::{from_raw_parts};

pub struct VecQueue<T> {
    list: Vec<T>,
    head: usize,
    tail: usize,
}

impl<T> VecQueue<T> {
    #[inline]
    pub fn new() -> Self { VecQueue::from(Vec::new()) }
    #[inline]
    pub fn pop(&mut self) -> T {
        debug_assert!(self.head < self.tail);
        self.head += 1;
        unsafe { ::std::ptr::read(self.list.as_mut_ptr().offset((self.head as isize) - 1)) }
    }
    #[inline]
    pub fn peek(&self) -> &T {
        debug_assert!(self.head < self.tail);
        unsafe { self.list.get_unchecked(self.head) }
    }
    #[inline]
    pub fn _peek_tail(&self) -> &T {
        debug_assert!(self.head < self.tail);
        unsafe { self.list.get_unchecked(self.tail-1) }
    }
    #[inline]
    pub fn _slice(&self) -> &[T] {
        debug_assert!(self.head < self.tail);
        unsafe { from_raw_parts(self.list.get_unchecked(self.head), self.tail - self.head) }
    }
    #[inline]
    pub fn from(mut list: Vec<T>) -> Self {
        let tail = list.len();
        unsafe { list.set_len(0); }
        VecQueue {
            list: list,
            head: 0,
            tail: tail,
        }
    }
    // could leak, if self.head != self.tail.
    #[inline]
    pub fn done(self) -> Vec<T> {
        debug_assert!(self.head == self.tail);
        self.list
    }
    #[inline]
    pub fn len(&self) -> usize { self.tail - self.head }
    #[inline]
    pub fn is_empty(&self) -> bool { self.head == self.tail }
}

#[inline]
unsafe fn push_unchecked<T>(vec: &mut Vec<T>, element: T) {
    debug_assert!(vec.len() < vec.capacity());
    let len = vec.len();
    ::std::ptr::write(vec.get_unchecked_mut(len), element);
    vec.set_len(len + 1);
}

pub struct MergeSorter<D: Ord, T: Ord, R: Monoid> {
    queue: Vec<Vec<Vec<(D, T, R)>>>,    // each power-of-two length list of allocations.
    stash: Vec<Vec<(D, T, R)>>,
}

impl<D: Ord, T: Ord, R: Monoid> MergeSorter<D, T, R> {

    #[inline]
    pub fn new() -> Self { MergeSorter { queue: Vec::new(), stash: Vec::new() } }

    #[inline]
    pub fn empty(&mut self) -> Vec<(D, T, R)> {
        self.stash.pop().unwrap_or_else(|| Vec::with_capacity(1024))
    }

    #[inline(never)]
    pub fn _sort(&mut self, list: &mut Vec<Vec<(D, T, R)>>) {
        for mut batch in list.drain(..) {
            self.push(&mut batch);
        }
        self.finish_into(list);
    }

    #[inline]
    pub fn push(&mut self, batch: &mut Vec<(D, T, R)>) {
        // TODO: Reason about possible unbounded stash growth. How to / should we return them?
        // TODO: Reason about mis-sized vectors, from deserialized data; should probably drop.
        let mut batch = if self.stash.len() > 2 {
            ::std::mem::replace(batch, self.stash.pop().unwrap())
        }
        else {
            ::std::mem::replace(batch, Vec::new())
        };

        if batch.len() > 0 {
            crate::consolidation::consolidate_updates(&mut batch);
            self.queue.push(vec![batch]);
            while self.queue.len() > 1 && (self.queue[self.queue.len()-1].len() >= self.queue[self.queue.len()-2].len() / 2) {
                let list1 = self.queue.pop().unwrap();
                let list2 = self.queue.pop().unwrap();
                let merged = self.merge_by(list1, list2);
                self.queue.push(merged);
            }
        }
    }

    // This is awkward, because it isn't a power-of-two length any more, and we don't want
    // to break it down to be so.
    pub fn push_list(&mut self, list: Vec<Vec<(D, T, R)>>) {
        while self.queue.len() > 1 && self.queue[self.queue.len()-1].len() < list.len() {
            let list1 = self.queue.pop().unwrap();
            let list2 = self.queue.pop().unwrap();
            let merged = self.merge_by(list1, list2);
            self.queue.push(merged);
        }
        self.queue.push(list);
    }

    #[inline(never)]
    pub fn finish_into(&mut self, target: &mut Vec<Vec<(D, T, R)>>) {
        while self.queue.len() > 1 {
            let list1 = self.queue.pop().unwrap();
            let list2 = self.queue.pop().unwrap();
            let merged = self.merge_by(list1, list2);
            self.queue.push(merged);
        }

        if let Some(mut last) = self.queue.pop() {
            ::std::mem::swap(&mut last, target);
        }
    }

    // merges two sorted input lists into one sorted output list.
    #[inline(never)]
    fn merge_by(&mut self, list1: Vec<Vec<(D, T, R)>>, list2: Vec<Vec<(D, T, R)>>) -> Vec<Vec<(D, T, R)>> {

        use std::cmp::Ordering;

        // TODO: `list1` and `list2` get dropped; would be better to reuse?
        let mut output = Vec::with_capacity(list1.len() + list2.len());
        let mut result = self.stash.pop().unwrap_or_else(|| Vec::with_capacity(1024));

        let mut list1 = VecQueue::from(list1);
        let mut list2 = VecQueue::from(list2);

        let mut head1 = if !list1.is_empty() { VecQueue::from(list1.pop()) } else { VecQueue::new() };
        let mut head2 = if !list2.is_empty() { VecQueue::from(list2.pop()) } else { VecQueue::new() };

        // while we have valid data in each input, merge.
        while !head1.is_empty() && !head2.is_empty() {

            while (result.capacity() - result.len()) > 0 && head1.len() > 0 && head2.len() > 0 {

                let cmp = {
                    let x = head1.peek();
                    let y = head2.peek();
                    (&x.0, &x.1).cmp(&(&y.0, &y.1))
                };
                match cmp {
                    Ordering::Less    => { unsafe { push_unchecked(&mut result, head1.pop()); } }
                    Ordering::Greater => { unsafe { push_unchecked(&mut result, head2.pop()); } }
                    Ordering::Equal   => {
                        let (data1, time1, mut diff1) = head1.pop();
                        let (_data2, _time2, diff2) = head2.pop();
                        diff1 += &diff2;
                        if !diff1.is_zero() {
                            unsafe { push_unchecked(&mut result, (data1, time1, diff1)); }
                        }
                    }
                }
            }

            if result.capacity() == result.len() {
                output.push(result);
                result = self.stash.pop().unwrap_or_else(|| Vec::with_capacity(1024));
            }

            if head1.is_empty() {
                let done1 = head1.done();
                if done1.capacity() == 1024 { self.stash.push(done1); }
                head1 = if !list1.is_empty() { VecQueue::from(list1.pop()) } else { VecQueue::new() };
            }
            if head2.is_empty() {
                let done2 = head2.done();
                if done2.capacity() == 1024 { self.stash.push(done2); }
                head2 = if !list2.is_empty() { VecQueue::from(list2.pop()) } else { VecQueue::new() };
            }
        }

        if result.len() > 0 { output.push(result); }
        else if result.capacity() > 0 { self.stash.push(result); }

        if !head1.is_empty() {
            let mut result = self.stash.pop().unwrap_or_else(|| Vec::with_capacity(1024));
            for _ in 0 .. head1.len() { result.push(head1.pop()); }
            output.push(result);
        }
        while !list1.is_empty() {
            output.push(list1.pop());
        }

        if !head2.is_empty() {
            let mut result = self.stash.pop().unwrap_or_else(|| Vec::with_capacity(1024));
            for _ in 0 .. head2.len() { result.push(head2.pop()); }
            output.push(result);
        }
        while !list2.is_empty() {
            output.push(list2.pop());
        }

        output
    }
}

/// Reports the number of elements satisfing the predicate.
///
/// This methods *relies strongly* on the assumption that the predicate
/// stays false once it becomes false, a joint property of the predicate
/// and the slice. This allows `advance` to use exponential search to
/// count the number of elements in time logarithmic in the result.
#[inline]
pub fn _advance<T, F: Fn(&T)->bool>(slice: &[T], function: F) -> usize {

	// start with no advance
	let mut index = 0;
	if index < slice.len() && function(&slice[index]) {

		// advance in exponentially growing steps.
		let mut step = 1;
		while index + step < slice.len() && function(&slice[index + step]) {
			index += step;
			step = step << 1;
		}

		// advance in exponentially shrinking steps.
		step = step >> 1;
		while step > 0 {
			if index + step < slice.len() && function(&slice[index + step]) {
				index += step;
			}
			step = step >> 1;
		}

		index += 1;
	}

	index
}
<commit_msg>guard freelist against ZSTs<commit_after>//! A general purpose `Batcher` implementation based on radix sort.

use timely::progress::frontier::Antichain;

use ::difference::Monoid;

use lattice::Lattice;
use trace::{Batch, Batcher, Builder};

/// Creates batches from unordered tuples.
pub struct MergeBatcher<K: Ord, V: Ord, T: Ord, R: Monoid, B: Batch<K, V, T, R>> {
    sorter: MergeSorter<(K, V), T, R>,
    lower: Vec<T>,
    frontier: Antichain<T>,
    phantom: ::std::marker::PhantomData<B>,
}

impl<K, V, T, R, B> Batcher<K, V, T, R, B> for MergeBatcher<K, V, T, R, B>
where
    K: Ord+Clone,
    V: Ord+Clone,
    T: Lattice+Ord+Clone,
    R: Monoid,
    B: Batch<K, V, T, R>,
{
    fn new() -> Self {
        MergeBatcher {
            sorter: MergeSorter::new(),
            frontier: Antichain::new(),
            lower: vec![T::minimum()],
            phantom: ::std::marker::PhantomData,
        }
    }

    #[inline(never)]
    fn push_batch(&mut self, batch: &mut Vec<((K,V),T,R)>) {
        self.sorter.push(batch);
    }

    // Sealing a batch means finding those updates with times not greater or equal to any time
    // in `upper`. All updates must have time greater or equal to the previously used `upper`,
    // which we call `lower`, by assumption that after sealing a batcher we receive no more
    // updates with times not greater or equal to `upper`.
    #[inline(never)]
    fn seal(&mut self, upper: &[T]) -> B {

        let mut builder = B::Builder::new();

        let mut merged = Vec::new();
        self.sorter.finish_into(&mut merged);

        let mut kept = Vec::new();
        let mut keep = Vec::new();

        self.frontier.clear();

        // TODO: Re-use buffer, rather than dropping.
        for mut buffer in merged.drain(..) {
            for ((key, val), time, diff) in buffer.drain(..) {
                if upper.iter().any(|t| t.less_equal(&time)) {
                    // keep_count += 1;
                    self.frontier.insert(time.clone());
                    if keep.len() == keep.capacity() {
                        if keep.len() > 0 {
                            kept.push(keep);
                            keep = self.sorter.empty();
                        }
                    }
                    keep.push(((key, val), time, diff));
                }
                else {
                    // seal_count += 1;
                    builder.push((key, val, time, diff));
                }
            }
            // Recycling buffer.
            self.sorter.push(&mut buffer);
        }

        // Finish the kept data.
        if keep.len() > 0 {
            kept.push(keep);
        }
        if kept.len() > 0 {
            self.sorter.push_list(kept);
        }

        // Drain buffers (fast reclaimation).
        // TODO : This isn't obviously the best policy, but "safe" wrt footprint.
        //        In particular, if we are reading serialized input data, we may
        //        prefer to keep these buffers around to re-fill, if possible.
        let mut buffer = Vec::new();
        self.sorter.push(&mut buffer);
        // We recycle buffers with allocations (capacity, and not zero-sized).
        while buffer.capacity() > 0 && std::mem::size_of::<((K,V),T,R)>() > 0 {
            buffer = Vec::new();
            self.sorter.push(&mut buffer);
        }

        let seal = builder.done(&self.lower[..], &upper[..], &self.lower[..]);
        self.lower = upper.to_vec();
        seal
    }

    // the frontier of elements remaining after the most recent call to `self.seal`.
    fn frontier(&mut self) -> &[T] {
        self.frontier.elements()
    }
}

use std::slice::{from_raw_parts};

pub struct VecQueue<T> {
    list: Vec<T>,
    head: usize,
    tail: usize,
}

impl<T> VecQueue<T> {
    #[inline]
    pub fn new() -> Self { VecQueue::from(Vec::new()) }
    #[inline]
    pub fn pop(&mut self) -> T {
        debug_assert!(self.head < self.tail);
        self.head += 1;
        unsafe { ::std::ptr::read(self.list.as_mut_ptr().offset((self.head as isize) - 1)) }
    }
    #[inline]
    pub fn peek(&self) -> &T {
        debug_assert!(self.head < self.tail);
        unsafe { self.list.get_unchecked(self.head) }
    }
    #[inline]
    pub fn _peek_tail(&self) -> &T {
        debug_assert!(self.head < self.tail);
        unsafe { self.list.get_unchecked(self.tail-1) }
    }
    #[inline]
    pub fn _slice(&self) -> &[T] {
        debug_assert!(self.head < self.tail);
        unsafe { from_raw_parts(self.list.get_unchecked(self.head), self.tail - self.head) }
    }
    #[inline]
    pub fn from(mut list: Vec<T>) -> Self {
        let tail = list.len();
        unsafe { list.set_len(0); }
        VecQueue {
            list: list,
            head: 0,
            tail: tail,
        }
    }
    // could leak, if self.head != self.tail.
    #[inline]
    pub fn done(self) -> Vec<T> {
        debug_assert!(self.head == self.tail);
        self.list
    }
    #[inline]
    pub fn len(&self) -> usize { self.tail - self.head }
    #[inline]
    pub fn is_empty(&self) -> bool { self.head == self.tail }
}

#[inline]
unsafe fn push_unchecked<T>(vec: &mut Vec<T>, element: T) {
    debug_assert!(vec.len() < vec.capacity());
    let len = vec.len();
    ::std::ptr::write(vec.get_unchecked_mut(len), element);
    vec.set_len(len + 1);
}

pub struct MergeSorter<D: Ord, T: Ord, R: Monoid> {
    queue: Vec<Vec<Vec<(D, T, R)>>>,    // each power-of-two length list of allocations.
    stash: Vec<Vec<(D, T, R)>>,
}

impl<D: Ord, T: Ord, R: Monoid> MergeSorter<D, T, R> {

    #[inline]
    pub fn new() -> Self { MergeSorter { queue: Vec::new(), stash: Vec::new() } }

    #[inline]
    pub fn empty(&mut self) -> Vec<(D, T, R)> {
        self.stash.pop().unwrap_or_else(|| Vec::with_capacity(1024))
    }

    #[inline(never)]
    pub fn _sort(&mut self, list: &mut Vec<Vec<(D, T, R)>>) {
        for mut batch in list.drain(..) {
            self.push(&mut batch);
        }
        self.finish_into(list);
    }

    #[inline]
    pub fn push(&mut self, batch: &mut Vec<(D, T, R)>) {
        // TODO: Reason about possible unbounded stash growth. How to / should we return them?
        // TODO: Reason about mis-sized vectors, from deserialized data; should probably drop.
        let mut batch = if self.stash.len() > 2 {
            ::std::mem::replace(batch, self.stash.pop().unwrap())
        }
        else {
            ::std::mem::replace(batch, Vec::new())
        };

        if batch.len() > 0 {
            crate::consolidation::consolidate_updates(&mut batch);
            self.queue.push(vec![batch]);
            while self.queue.len() > 1 && (self.queue[self.queue.len()-1].len() >= self.queue[self.queue.len()-2].len() / 2) {
                let list1 = self.queue.pop().unwrap();
                let list2 = self.queue.pop().unwrap();
                let merged = self.merge_by(list1, list2);
                self.queue.push(merged);
            }
        }
    }

    // This is awkward, because it isn't a power-of-two length any more, and we don't want
    // to break it down to be so.
    pub fn push_list(&mut self, list: Vec<Vec<(D, T, R)>>) {
        while self.queue.len() > 1 && self.queue[self.queue.len()-1].len() < list.len() {
            let list1 = self.queue.pop().unwrap();
            let list2 = self.queue.pop().unwrap();
            let merged = self.merge_by(list1, list2);
            self.queue.push(merged);
        }
        self.queue.push(list);
    }

    #[inline(never)]
    pub fn finish_into(&mut self, target: &mut Vec<Vec<(D, T, R)>>) {
        while self.queue.len() > 1 {
            let list1 = self.queue.pop().unwrap();
            let list2 = self.queue.pop().unwrap();
            let merged = self.merge_by(list1, list2);
            self.queue.push(merged);
        }

        if let Some(mut last) = self.queue.pop() {
            ::std::mem::swap(&mut last, target);
        }
    }

    // merges two sorted input lists into one sorted output list.
    #[inline(never)]
    fn merge_by(&mut self, list1: Vec<Vec<(D, T, R)>>, list2: Vec<Vec<(D, T, R)>>) -> Vec<Vec<(D, T, R)>> {

        use std::cmp::Ordering;

        // TODO: `list1` and `list2` get dropped; would be better to reuse?
        let mut output = Vec::with_capacity(list1.len() + list2.len());
        let mut result = self.stash.pop().unwrap_or_else(|| Vec::with_capacity(1024));

        let mut list1 = VecQueue::from(list1);
        let mut list2 = VecQueue::from(list2);

        let mut head1 = if !list1.is_empty() { VecQueue::from(list1.pop()) } else { VecQueue::new() };
        let mut head2 = if !list2.is_empty() { VecQueue::from(list2.pop()) } else { VecQueue::new() };

        // while we have valid data in each input, merge.
        while !head1.is_empty() && !head2.is_empty() {

            while (result.capacity() - result.len()) > 0 && head1.len() > 0 && head2.len() > 0 {

                let cmp = {
                    let x = head1.peek();
                    let y = head2.peek();
                    (&x.0, &x.1).cmp(&(&y.0, &y.1))
                };
                match cmp {
                    Ordering::Less    => { unsafe { push_unchecked(&mut result, head1.pop()); } }
                    Ordering::Greater => { unsafe { push_unchecked(&mut result, head2.pop()); } }
                    Ordering::Equal   => {
                        let (data1, time1, mut diff1) = head1.pop();
                        let (_data2, _time2, diff2) = head2.pop();
                        diff1 += &diff2;
                        if !diff1.is_zero() {
                            unsafe { push_unchecked(&mut result, (data1, time1, diff1)); }
                        }
                    }
                }
            }

            if result.capacity() == result.len() {
                output.push(result);
                result = self.stash.pop().unwrap_or_else(|| Vec::with_capacity(1024));
            }

            if head1.is_empty() {
                let done1 = head1.done();
                if done1.capacity() == 1024 { self.stash.push(done1); }
                head1 = if !list1.is_empty() { VecQueue::from(list1.pop()) } else { VecQueue::new() };
            }
            if head2.is_empty() {
                let done2 = head2.done();
                if done2.capacity() == 1024 { self.stash.push(done2); }
                head2 = if !list2.is_empty() { VecQueue::from(list2.pop()) } else { VecQueue::new() };
            }
        }

        if result.len() > 0 { output.push(result); }
        else if result.capacity() > 0 { self.stash.push(result); }

        if !head1.is_empty() {
            let mut result = self.stash.pop().unwrap_or_else(|| Vec::with_capacity(1024));
            for _ in 0 .. head1.len() { result.push(head1.pop()); }
            output.push(result);
        }
        while !list1.is_empty() {
            output.push(list1.pop());
        }

        if !head2.is_empty() {
            let mut result = self.stash.pop().unwrap_or_else(|| Vec::with_capacity(1024));
            for _ in 0 .. head2.len() { result.push(head2.pop()); }
            output.push(result);
        }
        while !list2.is_empty() {
            output.push(list2.pop());
        }

        output
    }
}

/// Reports the number of elements satisfing the predicate.
///
/// This methods *relies strongly* on the assumption that the predicate
/// stays false once it becomes false, a joint property of the predicate
/// and the slice. This allows `advance` to use exponential search to
/// count the number of elements in time logarithmic in the result.
#[inline]
pub fn _advance<T, F: Fn(&T)->bool>(slice: &[T], function: F) -> usize {

	// start with no advance
	let mut index = 0;
	if index < slice.len() && function(&slice[index]) {

		// advance in exponentially growing steps.
		let mut step = 1;
		while index + step < slice.len() && function(&slice[index + step]) {
			index += step;
			step = step << 1;
		}

		// advance in exponentially shrinking steps.
		step = step >> 1;
		while step > 0 {
			if index + step < slice.len() && function(&slice[index + step]) {
				index += step;
			}
			step = step >> 1;
		}

		index += 1;
	}

	index
}
<|endoftext|>


<commit_before>//! # Overview
//!
//! This crate provides native rust implementations of image encoding and decoding as well as some
//! basic image manipulation functions. Additional documentation can currently also be found in the
//! [README.md file which is most easily viewed on
//! github](https://github.com/image-rs/image/blob/master/README.md).
//!
//! There are two core problems for which this library provides solutions: a unified interface for image
//! encodings and simple generic buffers for their content. It's possible to use either feature
//! without the other. The focus is on a small and stable set of common operations that can be
//! supplemented by other specialized crates. The library also prefers safe solutions with few
//! dependencies.
//!
//! # High level API
//!
//! Load images using [`io::Reader`]:
//!
//! ```rust,no_run
//! # use std::io::Cursor;
//! use image::io::Reader as ImageReader;
//! # fn main() -> Result<(), image::ImageError> {
//! # let bytes = vec![0u8];
//!
//! let img = ImageReader::open("myimage.png")?.decode()?;
//! let img2 = ImageReader::new(Cursor::new(bytes)).decode()?;
//! # Ok(())
//! # }
//! ```
//!
//! And save them using [`save`] or [`write_to`] methods:
//!
//! ```rust,no_run
//! # use std::io::Write;
//! # use image::ImageOutputFormat;
//! # use image::DynamicImage;
//! # #[cfg(feature = "png")]
//! # fn main() -> Result<(), image::ImageError> {
//! # let img: DynamicImage = unimplemented!();
//! # let img2: DynamicImage = unimplemented!();
//! img.save("empty.jpg")?;
//!
//! let mut bytes: Vec<u8> = Vec::new();
//! img2.write_to(&mut bytes, image::ImageOutputFormat::Png)?;
//! # Ok(())
//! # }
//! # #[cfg(not(feature = "png"))] fn main() {}
//! ```
//!
//! With default features, the crate includes support for [many common image formats](codecs/index.html#supported-formats).
//!
//! [`save`]: enum.DynamicImage.html#method.save
//! [`write_to`]: enum.DynamicImage.html#method.write_to
//! [`io::Reader`]: io/struct.Reader.html
//!
//! # Image buffers
//!
//! The two main types for storing images:
//! * [`ImageBuffer`] which holds statically typed image contents.
//! * [`DynamicImage`] which is an enum over the supported ImageBuffer formats
//!     and supports conversions between them.
//!
//! As well as a few more specialized options:
//! * [`GenericImage`] trait for a mutable image buffer.
//! * [`GenericImageView`] trait for read only references to a GenericImage.
//! * [`flat`] module containing types for interoperability with generic channel
//!     matrices and foreign interfaces.
//!
//! [`GenericImageView`]: trait.GenericImageView.html
//! [`GenericImage`]: trait.GenericImage.html
//! [`ImageBuffer`]: struct.ImageBuffer.html
//! [`DynamicImage`]: enum.DynamicImage.html
//! [`flat`]: flat/index.html
//!
//! # Low level encoding/decoding API
//!
//! The [`ImageDecoder`] and [`ImageDecoderExt`] traits are implemented for many image file
//! formats. They decode image data by directly on raw byte slices. Given an ImageDecoder, you can
//! produce a DynamicImage via [`DynamicImage::from_decoder`].
//!
//! [`ImageEncoder`] provides the analogous functionality for encoding image data.
//!
//! [`DynamicImage::from_decoder`]: enum.DynamicImage.html#method.from_decoder
//! [`ImageDecoderExt`]: trait.ImageDecoderExt.html
//! [`ImageDecoder`]: trait.ImageDecoder.html
//! [`ImageEncoder`]: trait.ImageEncoder.html
#![warn(missing_docs)]
#![warn(unused_qualifications)]
#![deny(unreachable_pub)]
#![deny(deprecated)]
#![deny(missing_copy_implementations)]
#![cfg_attr(all(test, feature = "benchmarks"), feature(test))]
// it's a bit of a pain otherwise
#![allow(clippy::many_single_char_names)]
// it's a backwards compatibility break
#![allow(clippy::wrong_self_convention, clippy::enum_variant_names)]

#[cfg(all(test, feature = "benchmarks"))]
extern crate test;

#[cfg(test)]
#[macro_use]
extern crate quickcheck;

use std::io::Write;

pub use crate::color::{ColorType, ExtendedColorType};

pub use crate::color::{Luma, LumaA, Rgb, Rgba, Bgr, Bgra};

pub use crate::error::{ImageError, ImageResult};

pub use crate::image::{
    AnimationDecoder,
    GenericImage,
    GenericImageView,
    ImageDecoder,
    ImageDecoderExt,
    ImageEncoder,
    ImageFormat,
    ImageOutputFormat,
    Progress,
    // Iterators
    Pixels,
    SubImage
};

pub use crate::buffer_::{
    GrayAlphaImage,
    GrayImage,
    // Image types
    ImageBuffer,
    RgbImage,
    RgbaImage,
    Rgba32FImage,
    Rgb32FImage,
};

pub use crate::flat::FlatSamples;

// Traits
pub use crate::traits::{EncodableLayout, Primitive, Pixel};

// Opening and loading images
pub use crate::io::free_functions::{guess_format, load};
pub use crate::dynimage::{load_from_memory, load_from_memory_with_format, open,
                   save_buffer, save_buffer_with_format, write_buffer_with_format, image_dimensions};

pub use crate::dynimage::DynamicImage;

pub use crate::animation::{Delay, Frame, Frames};

// More detailed error type
pub mod error;

/// Iterators and other auxiliary structure for the `ImageBuffer` type.
pub mod buffer {
    // Only those not exported at the top-level
    pub use crate::buffer_::{
        ConvertBuffer,
        EnumeratePixels,
        EnumeratePixelsMut,
        EnumerateRows,
        EnumerateRowsMut,
        Pixels,
        PixelsMut,
        Rows,
        RowsMut,
    };
}

// Math utils
pub mod math;

// Image processing functions
pub mod imageops;

// Io bindings
pub mod io;

// Buffer representations for ffi.
pub mod flat;

/// Encoding and decoding for various image file formats.
///
/// # Supported formats
///
/// | Format | Decoding | Encoding |
/// | ------ | -------- | -------- |
/// | PNG    | All supported color types | Same as decoding |
/// | JPEG   | Baseline and progressive | Baseline JPEG |
/// | GIF    | Yes | Yes |
/// | BMP    | Yes | Rgb8, Rgba8, Gray8, GrayA8 |
/// | ICO    | Yes | Yes |
/// | TIFF   | Baseline(no fax support) + LZW + PackBits | Rgb8, Rgba8, Gray8 |
/// | WebP   | Lossy(Luma channel only) | No |
/// | AVIF   | Only 8-bit | Lossy |
/// | PNM    | PBM, PGM, PPM, standard PAM | Yes |
/// | DDS    | DXT1, DXT3, DXT5 | No |
/// | TGA    | Yes | Rgb8, Rgba8, Bgr8, Bgra8, Gray8, GrayA8 |
/// | OpenEXR  | Rgb32F, Rgba32F (no dwa compression) | Rgb32F, Rgba32F (no dwa compression) |
/// | farbfeld | Yes | Yes |
///
/// ## A note on format specific features
///
/// One of the main goals of `image` is stability, in runtime but also for programmers. This
/// ensures that performance as well as safety fixes reach a majority of its user base with little
/// effort. Re-exporting all details of its dependencies would run counter to this goal as it
/// linked _all_ major version bumps between them and `image`. As such, we are wary of exposing too
/// many details, or configuration options, that are not shared between different image formats.
///
/// Nevertheless, the advantage of precise control is hard to ignore. We will thus consider
/// _wrappers_, not direct re-exports, in either of the following cases:
///
/// 1. A standard specifies that configuration _x_ is required for decoders/encoders and there
///    exists an essentially canonical way to control it.
/// 2. At least two different implementations agree on some (sub-)set of features in practice.
/// 3. A technical argument including measurements of the performance, space benefits, or otherwise
///    objectively quantified benefits can be made, and the added interface is unlikely to require
///    breaking changes.
///
/// Features that fulfill two or more criteria are preferred.
///
/// Re-exports of dependencies that reach version `1` will be discussed when it happens.
pub mod codecs {
    #[cfg(any(feature = "avif-encoder", feature = "avif-decoder"))]
    pub mod avif;
    #[cfg(feature = "bmp")]
    pub mod bmp;
    #[cfg(feature = "dds")]
    pub mod dds;
    #[cfg(feature = "dxt")]
    pub mod dxt;
    #[cfg(feature = "farbfeld")]
    pub mod farbfeld;
    #[cfg(feature = "gif")]
    pub mod gif;
    #[cfg(feature = "hdr")]
    pub mod hdr;
    #[cfg(feature = "ico")]
    pub mod ico;
    #[cfg(feature = "jpeg")]
    pub mod jpeg;
    #[cfg(feature = "png")]
    pub mod png;
    #[cfg(feature = "pnm")]
    pub mod pnm;
    #[cfg(feature = "tga")]
    pub mod tga;
    #[cfg(feature = "tiff")]
    pub mod tiff;
    #[cfg(feature = "webp")]
    pub mod webp;
    #[cfg(feature = "openexr")]
    pub mod openexr;
}

#[cfg(feature = "avif-encoder")]
#[deprecated = "Use codecs::avif instead"]
pub mod avif {
    //! Encoding of AVIF images.
    pub use crate::codecs::avif::AvifEncoder;
}
#[cfg(feature = "bmp")]
#[deprecated = "Use codecs::bmp instead"]
pub mod bmp {
    //! Decoding and Encoding of BMP Images
    #[allow(deprecated)]
    pub use crate::codecs::bmp::{BMPEncoder, BmpDecoder, BmpEncoder};
}
#[cfg(feature = "dds")]
#[deprecated = "Use codecs::dds instead"]
pub mod dds {
    //! Decoding of DDS images
    pub use crate::codecs::dds::DdsDecoder;
}
#[cfg(feature = "dxt")]
#[deprecated = "Use codecs:: instead"]
pub mod dxt {
    //! Decoding of DXT (S3TC) compression
    #[allow(deprecated)]
    pub use crate::codecs::dxt::{
        DXTEncoder, DXTReader, DXTVariant, DxtDecoder, DxtEncoder, DxtReader, DxtVariant,
    };
}
#[cfg(feature = "farbfeld")]
#[deprecated = "Use codecs::farbfeld instead"]
pub mod farbfeld {
    //! Decoding of farbfeld images
    pub use crate::codecs::farbfeld::{FarbfeldDecoder, FarbfeldEncoder, FarbfeldReader};
}
#[cfg(feature = "gif")]
#[deprecated = "Use codecs::gif instead"]
pub mod gif {
    //! Decoding of GIF Images
    #[allow(deprecated)]
    pub use crate::codecs::gif::{Encoder, GifDecoder, GifEncoder, GifReader, Repeat};
}
#[cfg(feature = "hdr")]
#[deprecated = "Use codecs::hdr instead"]
pub mod hdr {
    //! Decoding of Radiance HDR Images
    #[allow(deprecated)]
    pub use crate::codecs::hdr::{
        read_raw_file, rgbe8, to_rgbe8, HDRAdapter, HDREncoder, HDRImageDecoderIterator,
        HDRMetadata, HdrAdapter, HdrDecoder, HdrEncoder, HdrImageDecoderIterator, HdrMetadata,
        HdrReader, RGBE8Pixel, Rgbe8Pixel, SIGNATURE,
    };
}
#[cfg(feature = "ico")]
#[deprecated = "Use codecs::ico instead"]
pub mod ico {
    //! Decoding and Encoding of ICO files
    #[allow(deprecated)]
    pub use crate::codecs::ico::{ICOEncoder, IcoDecoder, IcoEncoder};
}
#[cfg(feature = "jpeg")]
#[deprecated = "Use codecs::jpeg instead"]
pub mod jpeg {
    //! Decoding and Encoding of JPEG Images
    #[allow(deprecated)]
    pub use crate::codecs::jpeg::{
        JPEGEncoder, JpegDecoder, JpegEncoder, PixelDensity, PixelDensityUnit,
    };
}
#[cfg(feature = "png")]
#[deprecated = "Use codecs::png instead"]
pub mod png {
    //! Decoding and Encoding of PNG Images
    #[allow(deprecated)]
    pub use crate::codecs::png::{
        ApngDecoder, CompressionType, FilterType, PNGEncoder, PNGReader, PngDecoder, PngEncoder,
        PngReader,
    };
}
#[cfg(feature = "pnm")]
#[deprecated = "Use codecs::pnm instead"]
pub mod pnm {
    //! Decoding and Encoding of netpbm image formats (pbm, pgm, ppm and pam)
    #[allow(deprecated)]
    pub use crate::codecs::pnm::{
        ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PNMEncoder, PNMHeader,
        PNMSubtype, PixmapHeader, PnmDecoder, PnmEncoder, PnmHeader, PnmSubtype, SampleEncoding,
    };
}
#[cfg(feature = "tga")]
#[deprecated = "Use codecs::tga instead"]
pub mod tga {
    //! Decoding and Encoding of TGA Images
    #[allow(deprecated)]
    pub use crate::codecs::tga::{TgaDecoder, TgaEncoder};
}
#[cfg(feature = "tiff")]
#[deprecated = "Use codecs::tiff instead"]
pub mod tiff {
    //! Decoding and Encoding of TIFF Images
    #[allow(deprecated)]
    pub use crate::codecs::tiff::{TiffDecoder, TiffEncoder, TiffReader};
}
#[cfg(feature = "webp")]
#[deprecated = "Use codecs::webp instead"]
pub mod webp {
    //! Decoding of WebP Images
    #[allow(deprecated)]
    pub use crate::codecs::webp::{vp8, WebPDecoder};
}

mod animation;
#[path = "buffer.rs"]
mod buffer_;
mod color;
mod dynimage;
mod image;
mod traits;
mod utils;

// Can't use the macro-call itself within the `doc` attribute. So force it to eval it as part of
// the macro invocation.
//
// The inspiration for the macro and implementation is from
// <https://github.com/GuillaumeGomez/doc-comment>
//
// MIT License
//
// Copyright (c) 2018 Guillaume Gomez
macro_rules! insert_as_doc {
    { $content:expr } => {
        #[doc = $content] extern { }
    }
}

// Provides the README.md as doc, to ensure the example works!
insert_as_doc!(include_str!("../README.md"));

// Copies data from `src` to `dst`
//
// Panics if the length of `dst` is less than the length of `src`.
#[inline]
fn copy_memory(src: &[u8], mut dst: &mut [u8]) {
    let len_src = src.len();
    assert!(dst.len() >= len_src);
    dst.write_all(src).unwrap();
}
<commit_msg>Clarify use of ImageReader in top-level doc <commit_after>//! # Overview
//!
//! This crate provides native rust implementations of image encoding and decoding as well as some
//! basic image manipulation functions. Additional documentation can currently also be found in the
//! [README.md file which is most easily viewed on
//! github](https://github.com/image-rs/image/blob/master/README.md).
//!
//! There are two core problems for which this library provides solutions: a unified interface for image
//! encodings and simple generic buffers for their content. It's possible to use either feature
//! without the other. The focus is on a small and stable set of common operations that can be
//! supplemented by other specialized crates. The library also prefers safe solutions with few
//! dependencies.
//!
//! # High level API
//!
//! Load images using [`io::Reader`]:
//!
//! ```rust,no_run
//! # use std::io::Cursor;
//! use image::io::Reader as ImageReader;
//! # fn main() -> Result<(), image::ImageError> {
//! # let bytes = vec![0u8];
//!
//! let img = ImageReader::open("myimage.png")?.decode()?;
//! let img2 = ImageReader::new(Cursor::new(bytes)).with_guessed_format().decode()?;
//! # Ok(())
//! # }
//! ```
//!
//! And save them using [`save`] or [`write_to`] methods:
//!
//! ```rust,no_run
//! # use std::io::Write;
//! # use image::ImageOutputFormat;
//! # use image::DynamicImage;
//! # #[cfg(feature = "png")]
//! # fn main() -> Result<(), image::ImageError> {
//! # let img: DynamicImage = unimplemented!();
//! # let img2: DynamicImage = unimplemented!();
//! img.save("empty.jpg")?;
//!
//! let mut bytes: Vec<u8> = Vec::new();
//! img2.write_to(&mut bytes, image::ImageOutputFormat::Png)?;
//! # Ok(())
//! # }
//! # #[cfg(not(feature = "png"))] fn main() {}
//! ```
//!
//! With default features, the crate includes support for [many common image formats](codecs/index.html#supported-formats).
//!
//! [`save`]: enum.DynamicImage.html#method.save
//! [`write_to`]: enum.DynamicImage.html#method.write_to
//! [`io::Reader`]: io/struct.Reader.html
//!
//! # Image buffers
//!
//! The two main types for storing images:
//! * [`ImageBuffer`] which holds statically typed image contents.
//! * [`DynamicImage`] which is an enum over the supported ImageBuffer formats
//!     and supports conversions between them.
//!
//! As well as a few more specialized options:
//! * [`GenericImage`] trait for a mutable image buffer.
//! * [`GenericImageView`] trait for read only references to a GenericImage.
//! * [`flat`] module containing types for interoperability with generic channel
//!     matrices and foreign interfaces.
//!
//! [`GenericImageView`]: trait.GenericImageView.html
//! [`GenericImage`]: trait.GenericImage.html
//! [`ImageBuffer`]: struct.ImageBuffer.html
//! [`DynamicImage`]: enum.DynamicImage.html
//! [`flat`]: flat/index.html
//!
//! # Low level encoding/decoding API
//!
//! The [`ImageDecoder`] and [`ImageDecoderExt`] traits are implemented for many image file
//! formats. They decode image data by directly on raw byte slices. Given an ImageDecoder, you can
//! produce a DynamicImage via [`DynamicImage::from_decoder`].
//!
//! [`ImageEncoder`] provides the analogous functionality for encoding image data.
//!
//! [`DynamicImage::from_decoder`]: enum.DynamicImage.html#method.from_decoder
//! [`ImageDecoderExt`]: trait.ImageDecoderExt.html
//! [`ImageDecoder`]: trait.ImageDecoder.html
//! [`ImageEncoder`]: trait.ImageEncoder.html
#![warn(missing_docs)]
#![warn(unused_qualifications)]
#![deny(unreachable_pub)]
#![deny(deprecated)]
#![deny(missing_copy_implementations)]
#![cfg_attr(all(test, feature = "benchmarks"), feature(test))]
// it's a bit of a pain otherwise
#![allow(clippy::many_single_char_names)]
// it's a backwards compatibility break
#![allow(clippy::wrong_self_convention, clippy::enum_variant_names)]

#[cfg(all(test, feature = "benchmarks"))]
extern crate test;

#[cfg(test)]
#[macro_use]
extern crate quickcheck;

use std::io::Write;

pub use crate::color::{ColorType, ExtendedColorType};

pub use crate::color::{Luma, LumaA, Rgb, Rgba, Bgr, Bgra};

pub use crate::error::{ImageError, ImageResult};

pub use crate::image::{
    AnimationDecoder,
    GenericImage,
    GenericImageView,
    ImageDecoder,
    ImageDecoderExt,
    ImageEncoder,
    ImageFormat,
    ImageOutputFormat,
    Progress,
    // Iterators
    Pixels,
    SubImage
};

pub use crate::buffer_::{
    GrayAlphaImage,
    GrayImage,
    // Image types
    ImageBuffer,
    RgbImage,
    RgbaImage,
    Rgba32FImage,
    Rgb32FImage,
};

pub use crate::flat::FlatSamples;

// Traits
pub use crate::traits::{EncodableLayout, Primitive, Pixel};

// Opening and loading images
pub use crate::io::free_functions::{guess_format, load};
pub use crate::dynimage::{load_from_memory, load_from_memory_with_format, open,
                   save_buffer, save_buffer_with_format, write_buffer_with_format, image_dimensions};

pub use crate::dynimage::DynamicImage;

pub use crate::animation::{Delay, Frame, Frames};

// More detailed error type
pub mod error;

/// Iterators and other auxiliary structure for the `ImageBuffer` type.
pub mod buffer {
    // Only those not exported at the top-level
    pub use crate::buffer_::{
        ConvertBuffer,
        EnumeratePixels,
        EnumeratePixelsMut,
        EnumerateRows,
        EnumerateRowsMut,
        Pixels,
        PixelsMut,
        Rows,
        RowsMut,
    };
}

// Math utils
pub mod math;

// Image processing functions
pub mod imageops;

// Io bindings
pub mod io;

// Buffer representations for ffi.
pub mod flat;

/// Encoding and decoding for various image file formats.
///
/// # Supported formats
///
/// | Format | Decoding | Encoding |
/// | ------ | -------- | -------- |
/// | PNG    | All supported color types | Same as decoding |
/// | JPEG   | Baseline and progressive | Baseline JPEG |
/// | GIF    | Yes | Yes |
/// | BMP    | Yes | Rgb8, Rgba8, Gray8, GrayA8 |
/// | ICO    | Yes | Yes |
/// | TIFF   | Baseline(no fax support) + LZW + PackBits | Rgb8, Rgba8, Gray8 |
/// | WebP   | Lossy(Luma channel only) | No |
/// | AVIF   | Only 8-bit | Lossy |
/// | PNM    | PBM, PGM, PPM, standard PAM | Yes |
/// | DDS    | DXT1, DXT3, DXT5 | No |
/// | TGA    | Yes | Rgb8, Rgba8, Bgr8, Bgra8, Gray8, GrayA8 |
/// | OpenEXR  | Rgb32F, Rgba32F (no dwa compression) | Rgb32F, Rgba32F (no dwa compression) |
/// | farbfeld | Yes | Yes |
///
/// ## A note on format specific features
///
/// One of the main goals of `image` is stability, in runtime but also for programmers. This
/// ensures that performance as well as safety fixes reach a majority of its user base with little
/// effort. Re-exporting all details of its dependencies would run counter to this goal as it
/// linked _all_ major version bumps between them and `image`. As such, we are wary of exposing too
/// many details, or configuration options, that are not shared between different image formats.
///
/// Nevertheless, the advantage of precise control is hard to ignore. We will thus consider
/// _wrappers_, not direct re-exports, in either of the following cases:
///
/// 1. A standard specifies that configuration _x_ is required for decoders/encoders and there
///    exists an essentially canonical way to control it.
/// 2. At least two different implementations agree on some (sub-)set of features in practice.
/// 3. A technical argument including measurements of the performance, space benefits, or otherwise
///    objectively quantified benefits can be made, and the added interface is unlikely to require
///    breaking changes.
///
/// Features that fulfill two or more criteria are preferred.
///
/// Re-exports of dependencies that reach version `1` will be discussed when it happens.
pub mod codecs {
    #[cfg(any(feature = "avif-encoder", feature = "avif-decoder"))]
    pub mod avif;
    #[cfg(feature = "bmp")]
    pub mod bmp;
    #[cfg(feature = "dds")]
    pub mod dds;
    #[cfg(feature = "dxt")]
    pub mod dxt;
    #[cfg(feature = "farbfeld")]
    pub mod farbfeld;
    #[cfg(feature = "gif")]
    pub mod gif;
    #[cfg(feature = "hdr")]
    pub mod hdr;
    #[cfg(feature = "ico")]
    pub mod ico;
    #[cfg(feature = "jpeg")]
    pub mod jpeg;
    #[cfg(feature = "png")]
    pub mod png;
    #[cfg(feature = "pnm")]
    pub mod pnm;
    #[cfg(feature = "tga")]
    pub mod tga;
    #[cfg(feature = "tiff")]
    pub mod tiff;
    #[cfg(feature = "webp")]
    pub mod webp;
    #[cfg(feature = "openexr")]
    pub mod openexr;
}

#[cfg(feature = "avif-encoder")]
#[deprecated = "Use codecs::avif instead"]
pub mod avif {
    //! Encoding of AVIF images.
    pub use crate::codecs::avif::AvifEncoder;
}
#[cfg(feature = "bmp")]
#[deprecated = "Use codecs::bmp instead"]
pub mod bmp {
    //! Decoding and Encoding of BMP Images
    #[allow(deprecated)]
    pub use crate::codecs::bmp::{BMPEncoder, BmpDecoder, BmpEncoder};
}
#[cfg(feature = "dds")]
#[deprecated = "Use codecs::dds instead"]
pub mod dds {
    //! Decoding of DDS images
    pub use crate::codecs::dds::DdsDecoder;
}
#[cfg(feature = "dxt")]
#[deprecated = "Use codecs:: instead"]
pub mod dxt {
    //! Decoding of DXT (S3TC) compression
    #[allow(deprecated)]
    pub use crate::codecs::dxt::{
        DXTEncoder, DXTReader, DXTVariant, DxtDecoder, DxtEncoder, DxtReader, DxtVariant,
    };
}
#[cfg(feature = "farbfeld")]
#[deprecated = "Use codecs::farbfeld instead"]
pub mod farbfeld {
    //! Decoding of farbfeld images
    pub use crate::codecs::farbfeld::{FarbfeldDecoder, FarbfeldEncoder, FarbfeldReader};
}
#[cfg(feature = "gif")]
#[deprecated = "Use codecs::gif instead"]
pub mod gif {
    //! Decoding of GIF Images
    #[allow(deprecated)]
    pub use crate::codecs::gif::{Encoder, GifDecoder, GifEncoder, GifReader, Repeat};
}
#[cfg(feature = "hdr")]
#[deprecated = "Use codecs::hdr instead"]
pub mod hdr {
    //! Decoding of Radiance HDR Images
    #[allow(deprecated)]
    pub use crate::codecs::hdr::{
        read_raw_file, rgbe8, to_rgbe8, HDRAdapter, HDREncoder, HDRImageDecoderIterator,
        HDRMetadata, HdrAdapter, HdrDecoder, HdrEncoder, HdrImageDecoderIterator, HdrMetadata,
        HdrReader, RGBE8Pixel, Rgbe8Pixel, SIGNATURE,
    };
}
#[cfg(feature = "ico")]
#[deprecated = "Use codecs::ico instead"]
pub mod ico {
    //! Decoding and Encoding of ICO files
    #[allow(deprecated)]
    pub use crate::codecs::ico::{ICOEncoder, IcoDecoder, IcoEncoder};
}
#[cfg(feature = "jpeg")]
#[deprecated = "Use codecs::jpeg instead"]
pub mod jpeg {
    //! Decoding and Encoding of JPEG Images
    #[allow(deprecated)]
    pub use crate::codecs::jpeg::{
        JPEGEncoder, JpegDecoder, JpegEncoder, PixelDensity, PixelDensityUnit,
    };
}
#[cfg(feature = "png")]
#[deprecated = "Use codecs::png instead"]
pub mod png {
    //! Decoding and Encoding of PNG Images
    #[allow(deprecated)]
    pub use crate::codecs::png::{
        ApngDecoder, CompressionType, FilterType, PNGEncoder, PNGReader, PngDecoder, PngEncoder,
        PngReader,
    };
}
#[cfg(feature = "pnm")]
#[deprecated = "Use codecs::pnm instead"]
pub mod pnm {
    //! Decoding and Encoding of netpbm image formats (pbm, pgm, ppm and pam)
    #[allow(deprecated)]
    pub use crate::codecs::pnm::{
        ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PNMEncoder, PNMHeader,
        PNMSubtype, PixmapHeader, PnmDecoder, PnmEncoder, PnmHeader, PnmSubtype, SampleEncoding,
    };
}
#[cfg(feature = "tga")]
#[deprecated = "Use codecs::tga instead"]
pub mod tga {
    //! Decoding and Encoding of TGA Images
    #[allow(deprecated)]
    pub use crate::codecs::tga::{TgaDecoder, TgaEncoder};
}
#[cfg(feature = "tiff")]
#[deprecated = "Use codecs::tiff instead"]
pub mod tiff {
    //! Decoding and Encoding of TIFF Images
    #[allow(deprecated)]
    pub use crate::codecs::tiff::{TiffDecoder, TiffEncoder, TiffReader};
}
#[cfg(feature = "webp")]
#[deprecated = "Use codecs::webp instead"]
pub mod webp {
    //! Decoding of WebP Images
    #[allow(deprecated)]
    pub use crate::codecs::webp::{vp8, WebPDecoder};
}

mod animation;
#[path = "buffer.rs"]
mod buffer_;
mod color;
mod dynimage;
mod image;
mod traits;
mod utils;

// Can't use the macro-call itself within the `doc` attribute. So force it to eval it as part of
// the macro invocation.
//
// The inspiration for the macro and implementation is from
// <https://github.com/GuillaumeGomez/doc-comment>
//
// MIT License
//
// Copyright (c) 2018 Guillaume Gomez
macro_rules! insert_as_doc {
    { $content:expr } => {
        #[doc = $content] extern { }
    }
}

// Provides the README.md as doc, to ensure the example works!
insert_as_doc!(include_str!("../README.md"));

// Copies data from `src` to `dst`
//
// Panics if the length of `dst` is less than the length of `src`.
#[inline]
fn copy_memory(src: &[u8], mut dst: &mut [u8]) {
    let len_src = src.len();
    assert!(dst.len() >= len_src);
    dst.write_all(src).unwrap();
}
<|endoftext|>


<commit_before>//! A simple `io::stdoud` and `io::stderr` writing `Logger` implementation from the
//! `log` crate, using the `ansi_term` crate for colors and configured at runtime,
//! or at compile time with simple function calls. Designed for simple CLIs.
//!
//! This library only comes with 3 public ways to initialize the global logger.
//! Ensure you call one of these exactly once early in your rust program as shown
//! in one of the examples below.
//!
//! ## Example
//! The standard example with `clap` as the arg parser.
//!
//! ```
//! #[macro_use]
//! extern crate log;
//! extern crate clap;
//! extern crate loggerv;
//!
//! use loggerv as logger;
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let args = App::new("app")
//!                    .arg(Arg::with_name("v")
//!                             .short("v")
//!                             .multiple(true)
//!                             .help("Sets the level of verbosity"))
//!                    .get_matches();
//!
//!     logger::init_with_verbosity(args.occurrences_of("v")).unwrap();
//!
//!     error!("this is always printed");
//!     warn!("this too, and it's printed to stderr");
//!     info!("this is optional");  // for ./app -v or higher
//!     debug!("this is optional"); // for ./app -vv or higher
//!     trace!("this is optional"); // for ./app -vvv
//! }
//! ```
//!
//! But obviously use whatever argument parsing methods you prefer.
//!
//! ## Example
//! For a compile time switch, all you really need is `log` (for the macros)
//! and `loggerv` for how to print what's being sent to the macros.
//!
//! ```
//! #[macro_use]
//! extern crate log;
//! extern crate loggerv;
//!
//! use loggerv as logger;
//! use log::LogLevel;
//!
//! fn main() {
//!     logger::init_with_level(LogLevel::Info).unwrap();
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//! }
//! ```
//!
//! # Example
//! If you don't really care at all you could just use the plain `init` function
//! to only show warnings and errors:
//!
//! ```
//! #[macro_use]
//! extern crate log;
//! extern crate loggerv;
//!
//! use loggerv as logger;
//!
//! fn main() {
//!     logger::init().unwrap();
//!     info!("hidden");
//!     error!("this is printed by default");
//! }
//! ```
//!
//!
//! See the documentation for the log crate for more information about its API.
//!

extern crate log;
extern crate ansi_term;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};
use std::io::{self, Write};
use ansi_term::Colour;

struct VLogger {
    log_level: LogLevel,
}

fn level_style(l: LogLevel) -> Colour {
    match l {
        LogLevel::Error => Colour::Fixed(9), // bright red
        LogLevel::Warn => Colour::Fixed(11), // bright yellow
        LogLevel::Info => Colour::Fixed(10), // bright green
        LogLevel::Debug => Colour::Fixed(7), // light grey
        LogLevel::Trace => Colour::Fixed(8), // grey
    }
}

impl Log for VLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.log_level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let msg = format!("{}: {}",
                              level_style(record.level()).paint(record.location().module_path()),
                              record.args());
            if record.level() <= LogLevel::Warn {
                writeln!(&mut io::stderr(), "{}", msg);
            } else {
                println!("{}", msg);
            }
        }
    }
}

/// Initialize loggerv with a maximal log level.
///
/// See the main loggerv documentation page for an example.
pub fn init_with_level(log_level: LogLevel) -> Result<(), SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log_level.to_log_level_filter());
        Box::new(VLogger { log_level: log_level })
    })
}

/// Initialize loggerv with a verbosity level.
///
/// Intended to be used with an arg parser counting the amount of -v flags.
/// See the main loggerv documentation page for an example.
pub fn init_with_verbosity(verbosity: u64) -> Result<(), SetLoggerError> {
    init_with_level(match verbosity {
        0 => LogLevel::Warn,  // default
        1 => LogLevel::Info,  // -v
        2 => LogLevel::Debug, // -vv
        _ => LogLevel::Trace, // -vvv and above
    })
}

/// Initializes loggerv with only warnings and errors.
///
/// See the main loggerv documentation page for an example.
pub fn init() -> Result<(), SetLoggerError> {
    init_with_level(LogLevel::Warn)
}

#[cfg(test)]
mod tests {
    use init_with_verbosity;

    #[test]
    fn init_and_macros() {
        let l = init_with_verbosity(3);
        assert_eq!(l.is_ok(), true);
        //error!("error log");
        //warn!("warn log");
        //info!("info log");
        //debug!("debug log");
        //trace!("trace log");
    }
}
<commit_msg>make documentation less confusing<commit_after>//! A simple `io::stdoud` and `io::stderr` writing `Logger` implementation from the
//! `log` crate, using the `ansi_term` crate for colors and configured at runtime,
//! or at compile time with simple function calls. Designed for simple CLIs.
//!
//! This library only comes with 3 public ways to initialize the global logger.
//! Ensure you call one of these exactly once early in your rust program as shown
//! in one of the examples below.
//!
//! ## Example
//! The standard example with `clap` as the arg parser.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate clap;
//! extern crate loggerv;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let args = App::new("app")
//!                    .arg(Arg::with_name("v")
//!                             .short("v")
//!                             .multiple(true)
//!                             .help("Sets the level of verbosity"))
//!                    .get_matches();
//!
//!     loggerv::init_with_verbosity(args.occurrences_of("v")).unwrap();
//!
//!     error!("this is always printed");
//!     warn!("this too, and it's printed to stderr");
//!     info!("this is optional");  // for ./app -v or higher
//!     debug!("this is optional"); // for ./app -vv or higher
//!     trace!("this is optional"); // for ./app -vvv
//! }
//! ```
//!
//! But obviously use whatever argument parsing methods you prefer.
//!
//! ## Example
//! For a compile time switch, all you really need is `log` (for the macros)
//! and `loggerv` for how to print what's being sent to the macros.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! use log::LogLevel;
//!
//! fn main() {
//!     loggerv::init_with_level(LogLevel::Info).unwrap();
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//! }
//! ```
//!
//! # Example
//! If you don't really care at all you could just use the plain `init` function
//! to only show warnings and errors:
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! fn main() {
//!     loggerv::init().unwrap();
//!     info!("hidden");
//!     error!("this is printed by default");
//! }
//! ```
//!
//!
//! See the documentation for the log crate for more information about its API.
//!

extern crate log;
extern crate ansi_term;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};
use std::io::{self, Write};
use ansi_term::Colour;

struct VLogger {
    log_level: LogLevel,
}

fn level_style(l: LogLevel) -> Colour {
    match l {
        LogLevel::Error => Colour::Fixed(9), // bright red
        LogLevel::Warn => Colour::Fixed(11), // bright yellow
        LogLevel::Info => Colour::Fixed(10), // bright green
        LogLevel::Debug => Colour::Fixed(7), // light grey
        LogLevel::Trace => Colour::Fixed(8), // grey
    }
}

impl Log for VLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.log_level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let msg = format!("{}: {}",
                              level_style(record.level()).paint(record.location().module_path()),
                              record.args());
            if record.level() <= LogLevel::Warn {
                writeln!(&mut io::stderr(), "{}", msg);
            } else {
                println!("{}", msg);
            }
        }
    }
}

/// Initialize loggerv with a maximal log level.
///
/// See the main loggerv documentation page for an example.
pub fn init_with_level(log_level: LogLevel) -> Result<(), SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log_level.to_log_level_filter());
        Box::new(VLogger { log_level: log_level })
    })
}

/// Initialize loggerv with a verbosity level.
///
/// Intended to be used with an arg parser counting the amount of -v flags.
/// See the main loggerv documentation page for an example.
pub fn init_with_verbosity(verbosity: u64) -> Result<(), SetLoggerError> {
    init_with_level(match verbosity {
        0 => LogLevel::Warn,  // default
        1 => LogLevel::Info,  // -v
        2 => LogLevel::Debug, // -vv
        _ => LogLevel::Trace, // -vvv and above
    })
}

/// Initializes loggerv with only warnings and errors.
///
/// See the main loggerv documentation page for an example.
pub fn init() -> Result<(), SetLoggerError> {
    init_with_level(LogLevel::Warn)
}

#[cfg(test)]
mod tests {
    use init_with_verbosity;

    #[test]
    fn init_and_macros() {
        let l = init_with_verbosity(3);
        assert_eq!(l.is_ok(), true);
        //error!("error log");
        //warn!("warn log");
        //info!("info log");
        //debug!("debug log");
        //trace!("trace log");
    }
}
<|endoftext|>


<commit_before>extern crate lmdb;
extern crate lmdb_sys;

use std::{result, str};
use std::path::Path;
use lmdb::{Transaction, Cursor, DUP_SORT, INTEGER_KEY};

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum Error {
    DbCreateError,
    DbOpenError,
    DbWriteError,
    DbCorruptError,
    ParseError,
    TransactionError,
    PathError,
    NotFoundError,
}

pub type Result<T> = result::Result<T, Error>;

struct LmdbAdapter {
    env: lmdb::Environment,
    nodes: lmdb::Database,
    entries: lmdb::Database,
}

struct RwTransaction<'a> {
    lmdb_txn: lmdb::RwTransaction<'a>,
}

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
struct Id(u64);

struct Node<'a> {
    id: Id,
    parent_id: Id,
    name: &'a str,
}

struct Entry<'a> {
    txn: &'a RwTransaction<'a>,
    node: Node<'a>,
    objectclass: &'a str,
}

// Ids are 64-bit integers in host-native byte order
// LMDB has special optimizations for host-native integers as keys
impl Id {
    fn root() -> Id {
        Id(0)
    }

    fn from_bytes(bytes: &[u8]) -> Result<Id> {
        if bytes.len() != 8 {
            return Err(Error::ParseError);
        }

        let mut id = [0u8; 8];
        id.copy_from_slice(&bytes[0..8]);

        Ok(Id(unsafe { std::mem::transmute(id) }))
    }

    fn as_bytes(self) -> [u8; 8] {
        let Id(id) = self;
        unsafe { std::mem::transmute(id) }
    }

    fn next(self) -> Id {
        let Id(id) = self;
        Id(id + 1)
    }
}

impl<'a> Node<'a> {
    fn root() -> Node<'a> {
        Node {
            id: Id::root(),
            parent_id: Id::root(),
            name: "/",
        }
    }

    fn from_parent_id_and_bytes(parent_id: Id, bytes: &[u8]) -> Result<Node> {
        if bytes.len() < 8 {
            return Err(Error::DbCorruptError);
        }

        let id = try!(Id::from_bytes(&bytes[0..8]));
        let name = try!(std::str::from_utf8(&bytes[8..]).map_err(|_err| Error::DbCorruptError));

        Ok(Node {
            id: id,
            parent_id: parent_id,
            name: name,
        })
    }

    fn to_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(8 + self.name.len());
        bytes.extend_from_slice(&self.id.as_bytes());
        bytes.extend_from_slice(self.name.as_bytes());
        bytes
    }
}

impl LmdbAdapter {
    pub fn create_database(path: &Path) -> Result<LmdbAdapter> {
        let env = try!(lmdb::Environment::new()
                           .set_max_dbs(8)
                           .open_with_permissions(&path, 0o600)
                           .map_err(|_err| Error::DbCreateError));

        let nodes = try!(env.create_db(Some("nodes"), INTEGER_KEY | DUP_SORT)
                            .map_err(|_err| Error::DbCreateError));

        let entries = try!(env.create_db(Some("entries"), INTEGER_KEY)
                              .map_err(|_err| Error::DbCreateError));

        Ok(LmdbAdapter {
            env: env,
            nodes: nodes,
            entries: entries,
        })
    }

    pub fn open_database(path: &Path) -> Result<LmdbAdapter> {
        let env = try!(lmdb::Environment::new().open(&path).map_err(|_err| Error::DbOpenError));

        let nodes = try!(env.open_db(Some("nodes")).map_err(|_err| Error::DbOpenError));

        let entries = try!(env.open_db(Some("entries")).map_err(|_err| Error::DbOpenError));

        Ok(LmdbAdapter {
            env: env,
            nodes: nodes,
            entries: entries,
        })
    }

    pub fn rw_transaction(&self) -> Result<RwTransaction> {
        match self.env.begin_rw_txn() {
            Ok(txn) => Ok(RwTransaction { lmdb_txn: txn }),
            Err(_) => Err(Error::TransactionError),
        }
    }

    pub fn next_available_id(&self, txn: &mut RwTransaction) -> Result<Id> {
        let cursor = try!(txn.lmdb_txn
                             .open_rw_cursor(self.nodes)
                             .map_err(|_err| Error::TransactionError));

        let last_id = match cursor.get(None, None, lmdb_sys::MDB_LAST) {
            Ok((id, _)) => Id::from_bytes(id.unwrap()).unwrap(),
            Err(_) => Id::root(),
        };

        Ok(last_id.next())
    }

    pub fn create_entry<'a>(&'a self,
                            txn: &'a mut RwTransaction,
                            id: Id,
                            parent_id: Id,
                            name: &'a str,
                            objectclass: &'a str)
                            -> Result<Entry> {
        let node = Node {
            id: id,
            parent_id: parent_id,
            name: name,
        };

        try!(txn.lmdb_txn
                .put(self.nodes,
                     &parent_id.as_bytes(),
                     &node.to_bytes(),
                     lmdb::WriteFlags::empty())
                .map_err(|_err| Error::DbWriteError));

        try!(txn.lmdb_txn
                .put(self.entries,
                     &id.as_bytes(),
                     &objectclass,
                     lmdb::WriteFlags::empty())
                .map_err(|_err| Error::DbWriteError));

        Ok(Entry {
            txn: txn,
            node: node,
            objectclass: objectclass,
        })
    }

    pub fn find_entry<'a>(&'a self, txn: &'a RwTransaction, path: &str) -> Result<Entry> {
        let node = try!(self.find_node(txn, path));

        let entry_bytes = try!(txn.lmdb_txn
                                  .get(self.entries, &node.id.as_bytes())
                                  .map_err(|_err| Error::DbCorruptError));

        let objectclass = try!(std::str::from_utf8(&entry_bytes)
                                   .map_err(|_err| Error::DbCorruptError));

        Ok(Entry {
            txn: txn,
            node: node,
            objectclass: objectclass,
        })
    }

    fn find_node(&self, txn: &RwTransaction, path: &str) -> Result<Node> {
        let all_components: Vec<&str> = path.split("/").collect();

        if all_components.is_empty() {
            return Err(Error::PathError);
        }

        let (prefix, components) = all_components.split_first().unwrap();

        // Does the path start with something other than "/"?
        if !prefix.is_empty() {
            return Err(Error::PathError);
        }

        // Perform a hierarchical path lookup
        // TODO: since LMDB is ordered, we could e.g. perform a binary search
        components.iter().fold(Ok(Node::root()), |parent_node, component| {
            let parent_id = try!(parent_node).id;

            let mut cursor = try!(txn.lmdb_txn
                                     .open_ro_cursor(self.nodes)
                                     .map_err(|_err| Error::DbCorruptError));

            let mut child_node = None;

            for (id, node_bytes) in cursor.iter_from(parent_id.as_bytes()) {
                if id != parent_id.as_bytes() {
                    return Err(Error::NotFoundError);
                }

                let node = try!(Node::from_parent_id_and_bytes(parent_id, node_bytes));

                if node.name == *component {
                    child_node = Some(node);
                    break;
                }
            }

            child_node.ok_or(Error::NotFoundError)
        })
    }
}

impl<'a> RwTransaction<'a> {
    pub fn commit(self) -> Result<()> {
        self.lmdb_txn.commit().map_err(|_err| Error::TransactionError)
    }
}

#[test]
fn test_entry_lookup() {
    let path = Path::new("./tmp");
    let adapter = LmdbAdapter::create_database(path).unwrap();

    {
        let mut txn = adapter.rw_transaction().unwrap();

        let domain_id = adapter.next_available_id(&mut txn).unwrap();
        adapter.create_entry(&mut txn, domain_id, Id::root(), "example.com", "domain").unwrap();

        let hosts_id = domain_id.next();
        adapter.create_entry(&mut txn, hosts_id, domain_id, "hosts", "ou").unwrap();

        let host_id = hosts_id.next();
        adapter.create_entry(&mut txn, host_id, hosts_id, "master.example.com", "host").unwrap();

        txn.commit().unwrap();
    }

    {
        let txn = adapter.rw_transaction().unwrap();

        {
            let entry = adapter.find_entry(&txn, "/example.com/hosts/master.example.com")
                               .unwrap();

            assert_eq!(entry.node.name, "master.example.com");
            assert_eq!(entry.objectclass, "host");
        }

        txn.commit().unwrap();
    }
}
<commit_msg>Add pub exports to public APIs<commit_after>extern crate lmdb;
extern crate lmdb_sys;

use std::{result, str};
use std::path::Path;
use lmdb::{Transaction, Cursor, DUP_SORT, INTEGER_KEY};

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum Error {
    DbCreateError,
    DbOpenError,
    DbWriteError,
    DbCorruptError,
    ParseError,
    TransactionError,
    PathError,
    NotFoundError,
}

pub type Result<T> = result::Result<T, Error>;

pub struct LmdbAdapter {
    env: lmdb::Environment,
    nodes: lmdb::Database,
    entries: lmdb::Database,
}

pub struct RwTransaction<'a> {
    lmdb_txn: lmdb::RwTransaction<'a>,
}

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub struct Id(u64);

pub struct Node<'a> {
    pub id: Id,
    pub parent_id: Id,
    pub name: &'a str,
}

pub struct Entry<'a> {
    pub node: Node<'a>,
    pub objectclass: &'a str,
}

// Ids are 64-bit integers in host-native byte order
// LMDB has special optimizations for host-native integers as keys
impl Id {
    fn root() -> Id {
        Id(0)
    }

    fn from_bytes(bytes: &[u8]) -> Result<Id> {
        if bytes.len() != 8 {
            return Err(Error::ParseError);
        }

        let mut id = [0u8; 8];
        id.copy_from_slice(&bytes[0..8]);

        Ok(Id(unsafe { std::mem::transmute(id) }))
    }

    fn as_bytes(self) -> [u8; 8] {
        let Id(id) = self;
        unsafe { std::mem::transmute(id) }
    }

    fn next(self) -> Id {
        let Id(id) = self;
        Id(id + 1)
    }
}

impl<'a> Node<'a> {
    fn root() -> Node<'a> {
        Node {
            id: Id::root(),
            parent_id: Id::root(),
            name: "/",
        }
    }

    fn from_parent_id_and_bytes(parent_id: Id, bytes: &[u8]) -> Result<Node> {
        if bytes.len() < 8 {
            return Err(Error::DbCorruptError);
        }

        let id = try!(Id::from_bytes(&bytes[0..8]));
        let name = try!(std::str::from_utf8(&bytes[8..]).map_err(|_err| Error::DbCorruptError));

        Ok(Node {
            id: id,
            parent_id: parent_id,
            name: name,
        })
    }

    fn to_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(8 + self.name.len());
        bytes.extend_from_slice(&self.id.as_bytes());
        bytes.extend_from_slice(self.name.as_bytes());
        bytes
    }
}

impl LmdbAdapter {
    pub fn create_database(path: &Path) -> Result<LmdbAdapter> {
        let env = try!(lmdb::Environment::new()
                           .set_max_dbs(8)
                           .open_with_permissions(&path, 0o600)
                           .map_err(|_err| Error::DbCreateError));

        let nodes = try!(env.create_db(Some("nodes"), INTEGER_KEY | DUP_SORT)
                            .map_err(|_err| Error::DbCreateError));

        let entries = try!(env.create_db(Some("entries"), INTEGER_KEY)
                              .map_err(|_err| Error::DbCreateError));

        Ok(LmdbAdapter {
            env: env,
            nodes: nodes,
            entries: entries,
        })
    }

    pub fn open_database(path: &Path) -> Result<LmdbAdapter> {
        let env = try!(lmdb::Environment::new().open(&path).map_err(|_err| Error::DbOpenError));

        let nodes = try!(env.open_db(Some("nodes")).map_err(|_err| Error::DbOpenError));

        let entries = try!(env.open_db(Some("entries")).map_err(|_err| Error::DbOpenError));

        Ok(LmdbAdapter {
            env: env,
            nodes: nodes,
            entries: entries,
        })
    }

    pub fn rw_transaction(&self) -> Result<RwTransaction> {
        match self.env.begin_rw_txn() {
            Ok(txn) => Ok(RwTransaction { lmdb_txn: txn }),
            Err(_) => Err(Error::TransactionError),
        }
    }

    pub fn next_available_id(&self, txn: &mut RwTransaction) -> Result<Id> {
        let cursor = try!(txn.lmdb_txn
                             .open_rw_cursor(self.nodes)
                             .map_err(|_err| Error::TransactionError));

        let last_id = match cursor.get(None, None, lmdb_sys::MDB_LAST) {
            Ok((id, _)) => Id::from_bytes(id.unwrap()).unwrap(),
            Err(_) => Id::root(),
        };

        Ok(last_id.next())
    }

    pub fn create_entry<'a>(&'a self,
                            txn: &'a mut RwTransaction,
                            id: Id,
                            parent_id: Id,
                            name: &'a str,
                            objectclass: &'a str)
                            -> Result<Entry> {
        let node = Node {
            id: id,
            parent_id: parent_id,
            name: name,
        };

        try!(txn.lmdb_txn
                .put(self.nodes,
                     &parent_id.as_bytes(),
                     &node.to_bytes(),
                     lmdb::WriteFlags::empty())
                .map_err(|_err| Error::DbWriteError));

        try!(txn.lmdb_txn
                .put(self.entries,
                     &id.as_bytes(),
                     &objectclass,
                     lmdb::WriteFlags::empty())
                .map_err(|_err| Error::DbWriteError));

        Ok(Entry {
            node: node,
            objectclass: objectclass,
        })
    }

    pub fn find_entry<'a>(&'a self, txn: &'a RwTransaction, path: &str) -> Result<Entry> {
        let node = try!(self.find_node(txn, path));

        let entry_bytes = try!(txn.lmdb_txn
                                  .get(self.entries, &node.id.as_bytes())
                                  .map_err(|_err| Error::DbCorruptError));

        let objectclass = try!(std::str::from_utf8(&entry_bytes)
                                   .map_err(|_err| Error::DbCorruptError));

        Ok(Entry {
            node: node,
            objectclass: objectclass,
        })
    }

    fn find_node(&self, txn: &RwTransaction, path: &str) -> Result<Node> {
        let all_components: Vec<&str> = path.split("/").collect();

        if all_components.is_empty() {
            return Err(Error::PathError);
        }

        let (prefix, components) = all_components.split_first().unwrap();

        // Does the path start with something other than "/"?
        if !prefix.is_empty() {
            return Err(Error::PathError);
        }

        // Perform a hierarchical path lookup
        // TODO: since LMDB is ordered, we could e.g. perform a binary search
        components.iter().fold(Ok(Node::root()), |parent_node, component| {
            let parent_id = try!(parent_node).id;

            let mut cursor = try!(txn.lmdb_txn
                                     .open_ro_cursor(self.nodes)
                                     .map_err(|_err| Error::DbCorruptError));

            let mut child_node = None;

            for (id, node_bytes) in cursor.iter_from(parent_id.as_bytes()) {
                if id != parent_id.as_bytes() {
                    return Err(Error::NotFoundError);
                }

                let node = try!(Node::from_parent_id_and_bytes(parent_id, node_bytes));

                if node.name == *component {
                    child_node = Some(node);
                    break;
                }
            }

            child_node.ok_or(Error::NotFoundError)
        })
    }
}

impl<'a> RwTransaction<'a> {
    pub fn commit(self) -> Result<()> {
        self.lmdb_txn.commit().map_err(|_err| Error::TransactionError)
    }
}

#[test]
fn test_entry_lookup() {
    let path = Path::new("./tmp");
    let adapter = LmdbAdapter::create_database(path).unwrap();

    {
        let mut txn = adapter.rw_transaction().unwrap();

        let domain_id = adapter.next_available_id(&mut txn).unwrap();
        adapter.create_entry(&mut txn, domain_id, Id::root(), "example.com", "domain").unwrap();

        let hosts_id = domain_id.next();
        adapter.create_entry(&mut txn, hosts_id, domain_id, "hosts", "ou").unwrap();

        let host_id = hosts_id.next();
        adapter.create_entry(&mut txn, host_id, hosts_id, "master.example.com", "host").unwrap();

        txn.commit().unwrap();
    }

    {
        let txn = adapter.rw_transaction().unwrap();

        {
            let entry = adapter.find_entry(&txn, "/example.com/hosts/master.example.com")
                               .unwrap();

            assert_eq!(entry.node.name, "master.example.com");
            assert_eq!(entry.objectclass, "host");
        }

        txn.commit().unwrap();
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate maplit;
extern crate uuid;
extern crate serde;
extern crate serde_json;
#[macro_use]
mod macros;

pub use correlator::Correlator;
pub use config::action::ActionType;
pub use dispatcher::{Response};
pub use message::Message;

pub mod conditions;
pub mod config;
pub mod action;
mod condition;
mod context;
mod correlator;
mod dispatcher;
pub mod message;
mod state;
mod reactor;
mod timer;

pub type MiliSec = u32;
<commit_msg>lib: make 'condition' module public<commit_after>#[macro_use]
extern crate maplit;
extern crate uuid;
extern crate serde;
extern crate serde_json;
#[macro_use]
mod macros;

pub use correlator::Correlator;
pub use config::action::ActionType;
pub use dispatcher::{Response};
pub use message::Message;

pub mod conditions;
pub mod config;
pub mod action;
pub mod condition;
mod context;
mod correlator;
mod dispatcher;
pub mod message;
mod state;
mod reactor;
mod timer;

pub type MiliSec = u32;
<|endoftext|>


<commit_before>mod key;
mod rangeset;

use key::Key;
use rangeset::{Range, RangeSet};
use std::collections::HashMap;

pub type VKey = Key;
pub type EKey = Key;
pub type FKey = Key;
pub type FaceLen = u32;

pub struct Mesh {
    verts: HashMap<VKey, Vert>,
    edges: HashMap<EKey, Edge>,
    faces: HashMap<FKey, Face>,

    vert_range_set: RangeSet,
    edge_range_set: RangeSet,
    face_range_set: RangeSet
}

// TODO
fn new_key_range_set() -> RangeSet {
    RangeSet::new(Range::new(0, 0xffffffff - 1))
}

impl Mesh {
    pub fn new() -> Mesh {
        Mesh {
            verts: HashMap::new(),
            edges: HashMap::new(),
            faces: HashMap::new(),

            vert_range_set: new_key_range_set(),
            edge_range_set: new_key_range_set(),
            face_range_set: new_key_range_set()
        }
    }

    /// Return the edge between two verts, or None if no such edge
    /// exists.
    pub fn find_edge(&self, vk0: VKey, vk1: VKey) -> Option<EKey> {
        for ek in self.verts[&vk0].edges.iter() {
            if self.edges[ek].is_vert_adjacent(vk1) {
                return Some(*ek)
            }
        }
        None
    }

    /// Add a new isolated vertex and return its key. Fail and return
    /// None if there are no more vertex keys available.
    pub fn add_vert(&mut self) -> Option<VKey> {
        if let Some(val) = self.vert_range_set.take_any_one() {
            let vkey = VKey::new(val);
            self.verts.insert(vkey, Vert::new());
            Some(vkey)
        } else {
            None
        }
    }

    pub fn add_edge(&mut self, vk0: VKey, vk1: VKey) -> Option<EKey> {
        // TODO(nicholasbishop): check that the verts are in the mesh,
        if vk0 == vk1 {
            None
        } else if let Some(ek) = self.find_edge(vk0, vk1) {
            Some(ek)
        } else {
            if let Some(val) = self.edge_range_set.take_any_one() {
                let ekey = EKey::new(val);
                self.verts.get_mut(&vk0).unwrap().push_edge(ekey);
                self.verts.get_mut(&vk1).unwrap().push_edge(ekey);
                self.edges.insert(ekey, Edge::new(vk0, vk1));
                Some(ekey)
            } else {
                None
            }
        }
    }

    pub fn add_face(&mut self, vk: &[VKey]) -> Option<FKey> {
        let mut loops = Vec::with_capacity(vk.len());
        for i in 0..vk.len() {
            let vk0 = vk[i];
            let vk1 = vk[if i < (vk.len() - 1) { i + 1 } else { 0 }];
            // TODO(nicholasbishop): do more checking up front so that
            // edges don't get created on failure, or delete them after.
            if let Some(ek) = self.add_edge(vk0, vk1) {
                loops.push(Loop { vert: vk0, edge: ek });
            } else {
                // Error: failed to create edge
                return None;
            }
        }
        if let Some(val) = self.face_range_set.take_any_one() {
            let fk = FKey::new(val);
            for lp in loops.iter() {
                self.edges.get_mut(&lp.edge).unwrap().push_face(fk);
            }
            self.faces.insert(fk, Face::new(loops));
            Some(fk)
        } else {
            None
        }
    }
}

pub struct Vert {
    edges: Vec<EKey>
}

impl Vert {
    fn new() -> Vert {
        Vert { edges: Vec::new() }
    }

    /// Check if the edge is in the set of edges adjacent to this vert.
    pub fn is_edge_adjacent(&self, ek: EKey) -> bool {
        self.edges.contains(&ek)
    }

    /// Add edge to set of edges adjacent to the vert. Does nothing if
    /// the edge is already in the set.
    fn push_edge(&mut self, ek: EKey) {
        if !self.is_edge_adjacent(ek) {
            self.edges.push(ek);
        }
    }
}

pub struct Edge {
    verts: [VKey; 2],
    faces: Vec<FKey>
}

impl Edge {
    fn new(vk0: VKey, vk1: VKey) -> Edge {
        Edge { verts: [vk0, vk1], faces: Vec::new() }
    }

    /// Check if the vert is one of the two verts adjacent to this edge.
    fn is_vert_adjacent(&self, vk: VKey) -> bool {
        self.verts.contains(&vk)
    }

    /// Check if the face is in the set of edges adjacent to this edge.
    pub fn is_face_adjacent(&self, fk: FKey) -> bool {
        self.faces.contains(&fk)
    }

    /// Add face to set of faces adjacent to the edge. Does nothing if
    /// the face is already in the set.
    fn push_face(&mut self, fk: FKey) {
        if !self.is_face_adjacent(fk) {
            self.faces.push(fk);
        }
    }
}

pub struct Loop {
    vert: VKey,
    edge: EKey,
}

pub struct Face {
    loops: Vec<Loop>
}

impl Face {
    fn new(loops: Vec<Loop>) -> Face {
        Face { loops: loops }
    }
}

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

    #[test]
    fn test_add_vert() {
        let mut mesh = Mesh::new();
        assert!(mesh.add_vert().is_some());
        assert!(!mesh.verts.is_empty());
    }

    #[test]
    fn test_add_edge() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert().unwrap();
        let b = mesh.add_vert().unwrap();

        // Add a valid edge
        let e = mesh.add_edge(a, b).unwrap();
        assert!(mesh.verts[&a].edges.contains(&e));
        assert!(mesh.verts[&b].edges.contains(&e));

        // Edge from a vertex to the same vertex is not allowed
        assert!(mesh.add_edge(a, a).is_none());

        // Duplicate edge should return the existing edge
        assert_eq!(mesh.add_edge(a, b).unwrap(), e);
        assert_eq!(mesh.add_edge(b, a).unwrap(), e);
    }

    #[test]
    fn test_add_face() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert().unwrap();
        let b = mesh.add_vert().unwrap();
        let c = mesh.add_vert().unwrap();

        // Add a valid triangle
        mesh.add_face(&[a, b, c]).unwrap();
        assert_eq!(mesh.edges.len(), 3);
        // TODO(nicholasbishop): check adj

        // Add an invalid triangle with invalid edge
        assert!(mesh.add_face(&[a, b, b]).is_none());
    }
}
<commit_msg>Expand test<commit_after>mod key;
mod rangeset;

use key::Key;
use rangeset::{Range, RangeSet};
use std::collections::HashMap;

pub type VKey = Key;
pub type EKey = Key;
pub type FKey = Key;
pub type FaceLen = u32;

pub struct Mesh {
    verts: HashMap<VKey, Vert>,
    edges: HashMap<EKey, Edge>,
    faces: HashMap<FKey, Face>,

    vert_range_set: RangeSet,
    edge_range_set: RangeSet,
    face_range_set: RangeSet
}

// TODO
fn new_key_range_set() -> RangeSet {
    RangeSet::new(Range::new(0, 0xffffffff - 1))
}

impl Mesh {
    pub fn new() -> Mesh {
        Mesh {
            verts: HashMap::new(),
            edges: HashMap::new(),
            faces: HashMap::new(),

            vert_range_set: new_key_range_set(),
            edge_range_set: new_key_range_set(),
            face_range_set: new_key_range_set()
        }
    }

    /// Return the edge between two verts, or None if no such edge
    /// exists.
    pub fn find_edge(&self, vk0: VKey, vk1: VKey) -> Option<EKey> {
        for ek in self.verts[&vk0].edges.iter() {
            if self.edges[ek].is_vert_adjacent(vk1) {
                return Some(*ek)
            }
        }
        None
    }

    /// Add a new isolated vertex and return its key. Fail and return
    /// None if there are no more vertex keys available.
    pub fn add_vert(&mut self) -> Option<VKey> {
        if let Some(val) = self.vert_range_set.take_any_one() {
            let vkey = VKey::new(val);
            self.verts.insert(vkey, Vert::new());
            Some(vkey)
        } else {
            None
        }
    }

    pub fn add_edge(&mut self, vk0: VKey, vk1: VKey) -> Option<EKey> {
        // TODO(nicholasbishop): check that the verts are in the mesh,
        if vk0 == vk1 {
            None
        } else if let Some(ek) = self.find_edge(vk0, vk1) {
            Some(ek)
        } else {
            if let Some(val) = self.edge_range_set.take_any_one() {
                let ekey = EKey::new(val);
                self.verts.get_mut(&vk0).unwrap().push_edge(ekey);
                self.verts.get_mut(&vk1).unwrap().push_edge(ekey);
                self.edges.insert(ekey, Edge::new(vk0, vk1));
                Some(ekey)
            } else {
                None
            }
        }
    }

    pub fn add_face(&mut self, vk: &[VKey]) -> Option<FKey> {
        let mut loops = Vec::with_capacity(vk.len());
        for i in 0..vk.len() {
            let vk0 = vk[i];
            let vk1 = vk[if i < (vk.len() - 1) { i + 1 } else { 0 }];
            // TODO(nicholasbishop): do more checking up front so that
            // edges don't get created on failure, or delete them after.
            if let Some(ek) = self.add_edge(vk0, vk1) {
                loops.push(Loop { vert: vk0, edge: ek });
            } else {
                // Error: failed to create edge
                return None;
            }
        }
        if let Some(val) = self.face_range_set.take_any_one() {
            let fk = FKey::new(val);
            for lp in loops.iter() {
                self.edges.get_mut(&lp.edge).unwrap().push_face(fk);
            }
            self.faces.insert(fk, Face::new(loops));
            Some(fk)
        } else {
            None
        }
    }
}

pub struct Vert {
    edges: Vec<EKey>
}

impl Vert {
    fn new() -> Vert {
        Vert { edges: Vec::new() }
    }

    /// Check if the edge is in the set of edges adjacent to this vert.
    pub fn is_edge_adjacent(&self, ek: EKey) -> bool {
        self.edges.contains(&ek)
    }

    /// Add edge to set of edges adjacent to the vert. Does nothing if
    /// the edge is already in the set.
    fn push_edge(&mut self, ek: EKey) {
        if !self.is_edge_adjacent(ek) {
            self.edges.push(ek);
        }
    }
}

pub struct Edge {
    verts: [VKey; 2],
    faces: Vec<FKey>
}

impl Edge {
    fn new(vk0: VKey, vk1: VKey) -> Edge {
        Edge { verts: [vk0, vk1], faces: Vec::new() }
    }

    /// Check if the vert is one of the two verts adjacent to this edge.
    fn is_vert_adjacent(&self, vk: VKey) -> bool {
        self.verts.contains(&vk)
    }

    /// Check if the face is in the set of edges adjacent to this edge.
    pub fn is_face_adjacent(&self, fk: FKey) -> bool {
        self.faces.contains(&fk)
    }

    /// Add face to set of faces adjacent to the edge. Does nothing if
    /// the face is already in the set.
    fn push_face(&mut self, fk: FKey) {
        if !self.is_face_adjacent(fk) {
            self.faces.push(fk);
        }
    }
}

pub struct Loop {
    vert: VKey,
    edge: EKey,
}

pub struct Face {
    loops: Vec<Loop>
}

impl Face {
    fn new(loops: Vec<Loop>) -> Face {
        Face { loops: loops }
    }
}

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

    #[test]
    fn test_add_vert() {
        let mut mesh = Mesh::new();
        assert!(mesh.add_vert().is_some());
        assert!(!mesh.verts.is_empty());
    }

    #[test]
    fn test_add_edge() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert().unwrap();
        let b = mesh.add_vert().unwrap();

        // Add a valid edge
        let e = mesh.add_edge(a, b).unwrap();
        assert!(mesh.verts[&a].edges.contains(&e));
        assert!(mesh.verts[&b].edges.contains(&e));

        // Edge from a vertex to the same vertex is not allowed
        assert!(mesh.add_edge(a, a).is_none());

        // Duplicate edge should return the existing edge
        assert_eq!(mesh.add_edge(a, b).unwrap(), e);
        assert_eq!(mesh.add_edge(b, a).unwrap(), e);
    }

    #[test]
    fn test_add_face() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert().unwrap();
        let b = mesh.add_vert().unwrap();
        let c = mesh.add_vert().unwrap();

        // Add a valid triangle
        let fk = mesh.add_face(&[a, b, c]).unwrap();
        assert_eq!(mesh.edges.len(), 3);
        for lp in mesh.faces[&fk].loops.iter() {
            assert!(mesh.edges[&lp.edge].is_face_adjacent(fk));
        }

        // Add an invalid triangle with invalid edge
        assert!(mesh.add_face(&[a, b, b]).is_none());
    }
}
<|endoftext|>