<commit_before>//! Atom-class implementation.

use std::ops::{BitXor, Sub, Range, RangeInclusive};
use std::iter::FromIterator;
use std::fmt::{self, Debug};

use regex_syntax;
use itertools::Itertools;

use super::{Anchor, Atom, ByteOrChar, Element, Repetition, Sequence, Union};
use super::{Distance, Step};
use util::set::{self, Contains};

// ----------------------------------------------------------------
// Class

/// Any member of a class of atoms
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub enum ClassMember<T: Atom> {
    /// A single atom
    Atom(T),

    /// A range of atoms
    Range(T, T)
}

impl<T: Atom> ClassMember<T> {
    /// Map the class-member's atoms to a different type
    pub fn map_atoms<U, F>(self, f: F) -> ClassMember<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        match self {
            ClassMember::Atom(a) => ClassMember::Atom(f(a)),
            ClassMember::Range(a, b) => ClassMember::Range(f(a), f(b))
        }
    }

    /// Get the number of individual atoms that this class member represents.
    pub fn len(&self) -> usize
        where T: Distance
    {
        match self {
            &ClassMember::Atom(_) => 1,
            &ClassMember::Range(first, last) => last.distance(&first) + 1,
        }
    }

    /// Fetch an iterator over each discrete value contained by this member.
    #[inline]
     pub fn iter(&self) -> impl Iterator<Item=T>
        where T: Step {
        match self {
            &ClassMember::Atom(a) => AtomIter(a...a),
            &ClassMember::Range(a, b) => AtomIter(a...b),
        }
    }
}

impl<T: Atom> set::Contains<T> for ClassMember<T> {
    /// Check if the member is or contains a particular atom.
    fn contains(&self, x: T) -> bool {
        match self {
            &ClassMember::Atom(a) => x == a,
            &ClassMember::Range(a, b) => (a...b).contains(x),
        }
    }
}

/// Iterator over the atoms specified by a class member.
struct AtomIter<T: Atom>(RangeInclusive<T>);

impl<T: Atom> Iterator for AtomIter<T>
        where T: Step
{
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        match self.0 {
            RangeInclusive::NonEmpty{start, end} => {
                let next_start = start.increment();
                if next_start > end {
                    self.0 = RangeInclusive::Empty{at: end};
                } else {
                    self.0 = RangeInclusive::NonEmpty{start: next_start, end: end};
                }
                Some(start) },
            RangeInclusive::Empty{..} => None
        }
    }
}

/*impl<T: Atom> Debug for ClassMember<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ClassMember::Atom(a) => write!(f, "{:?}", a),
            ClassMember::Range(first, last) => write!(f, "{:?}-{:?}", first, last)
        }
    }
}*/

impl<T: Atom> From<T> for ClassMember<T> {
    fn from(a: T) -> Self { ClassMember::Atom(a) }
}

impl From<regex_syntax::ClassRange> for ClassMember<ByteOrChar> {
    fn from(cr: regex_syntax::ClassRange) -> Self {
        ClassMember::Range(cr.start.into(), cr.end.into())
    }
}

impl From<regex_syntax::ByteRange> for ClassMember<ByteOrChar> {
    fn from(cr: regex_syntax::ByteRange) -> Self {
        ClassMember::Range(cr.start.into(), cr.end.into())
    }
}

impl From<regex_syntax::ClassRange> for ClassMember<char> {
    fn from(cr: regex_syntax::ClassRange) -> Self {
        ClassMember::Range(cr.start, cr.end)
    }
}

impl From<regex_syntax::ByteRange> for ClassMember<u8> {
    fn from(cr: regex_syntax::ByteRange) -> Self {
        ClassMember::Range(cr.start, cr.end)
    }
}

impl<T: Atom> From<Range<T>> for ClassMember<T>
    where T: Sub<usize,Output=T> + Sub<T,Output=usize>
{
    fn from(r: Range<T>) -> Self {
        if r.end - r.start > 1 { ClassMember::Range(r.start, r.end - 1usize) }
        else { ClassMember::Atom(r.start) }
    }
}
// ----------------------------------------------------------------

/// A set of atoms and/or ranges of atoms.
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct Class<T: Atom> {
    polarity: Polarity,
    members: Vec<ClassMember<T>>
}

// FIXME: [optimize] All operations on a Class<T>, including observer and
// predicate methods, currently require at least O(N) time.  We could probably
// improve this by changing the storage representation.
impl<T: Atom> Class<T> {
    /// Create a new Class instance with specified polarity and members taken
    /// from the given iterator.
    pub fn new<I,U>(p: Polarity, items: I) -> Self
        where I: IntoIterator<Item=U>,
              ClassMember<T>: From<U> {
        Class{polarity: p, members: Vec::from_iter(items.into_iter().map(|x| x.into()))}
    }

    /// Create a new Class instance from an iterator of ClassMember instances.
    pub fn from_members<I>(m: I) -> Self
        where I: IntoIterator<Item=ClassMember<T>>
    {
        Class{polarity: Polarity::NORMAL, members: m.into_iter().collect()}
    }

    /// Map the atoms in the class to a different atom type.
    pub fn map_atoms<U, F>(self, f: F) -> Class<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        Class::new(self.polarity, self.members.into_iter().map(|m| m.map_atoms(&f)))
    }

    /// Check whether the class would match a particular atom.
    pub fn matches(&self, x: T) -> bool {
        self.has_member(x).bitxor(self.polarity == Polarity::INVERTED)
    }

    /// Check whether a particular atom is a member of this class.
    /// Unlike `matches`, this method does not take the class's polarity
    /// into account.
    pub fn has_member(&self, x: T) -> bool {
        self.members.iter().any(|&range| range.contains(x))
    }

    /// Get the number of members (atoms) in the class.
    ///
    /// Ranges of atoms count as the number of atoms in each range.
    // FIXME: [bug] handle inverted polarity?
    pub fn len(&self) -> usize {
        self.members.iter().map(|m| m.len()).sum()
    }

    /// Get the class's polarity.
    #[inline]
    pub fn polarity(&self) -> Polarity {
        self.polarity
    }

    /// Check if the class contains zero members.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.members.is_empty()
    }

    /// Fetch an iterator over the members specified in the class.
    ///
    /// Note that if the class has inverted polarity, the atoms in these
    /// members will be those which are **not** matched by the class.
    pub fn iter_members<'a>(&'a self) -> impl Iterator<Item=&'a ClassMember<T>> {
        self.members.iter()
    }

    /// Fetch an iterator over the atoms specified in the class.
    ///
    /// Note that if the class has inverted polarity, these will be those atoms
    /// which are **not** matched by the class.
    pub fn iter<'a>(&'a self) -> impl Iterator<Item=T> + 'a {
        self.members.iter().flat_map(|m| m.iter())
    }
}

impl<T: Atom> Debug for Class<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.polarity == Polarity::NORMAL {
            write!(f, "[{}]", self.members.iter().map(|m| format!("{:?}", m)).join(","))
        } else {
            write!(f, "[^{}]", self.members.iter().map(|m| format!("{:?}", m)).join(","))
        }
    }
}

impl<'a, T: 'a + Atom> set::Contains<&'a ClassMember<T>> for Class<T> {
    fn contains(&self, cm: &'a ClassMember<T>) -> bool {
        self.iter_members().any(|m| cm == m)
    }
}
impl<T: Atom> set::Contains<T> for Class<T> {
    /// Check if any member of the class matches the given atom.
    fn contains(&self, x: T) -> bool {
        self.matches(x)
    }
}

impl<T: Atom> set::IsSubsetOf<T> for Class<T> {
    /// A class *can* be a subset of an atom -- as long as that atom is the
    /// only member of the class!
    #[inline]
    fn is_subset_of(&self, atom: &T) -> bool {
        self.contains(*atom) && self.polarity == Polarity::NORMAL && self.len() == 1
    }
}

impl<T: Atom> set::IsSubsetOf<Anchor<T>> for Class<T> {
    /// A class is never a subset of an anchor.
    #[inline(always)]
    fn is_subset_of(&self, _: &Anchor<T>) -> bool {
        false
    }
}

// FIXME [optimize] I suspect that we need some sort of specialized data
// structure or clever algorithm in order to perform this test in a time better
// than O(N·M).
impl<T: Atom> set::IsSubsetOf<Class<T>> for Class<T> {
    /// A class `A` is a subset of another class `B` if all atoms in `A` are
    /// also in `B`.
    fn is_subset_of(&self, other: &Self) -> bool {
        self.iter().all(|a| other.contains(a))
    }
}
impl<T: Atom> set::IsSubsetOf<Sequence<T>> for Class<T> {
    /// Any single-atom pattern like Class cannot match the same set of inputs
    /// as a Sequence, because a Sequence is guaranteed to contain at least
    /// two elements.
    #[inline]
    fn is_subset_of(&self, _: &Sequence<T>) -> bool {
        false
    }
}

impl<T: Atom> set::IsSubsetOf<Union<T>> for Class<T> {
    /// A class is a subset of a union if all members of the class are subsets
    /// of the union.
    fn is_subset_of(&self, union: &Union<T>) -> bool {
        self.iter().all(|a| a.is_subset_of(union))
    }
}

impl<T: Atom> set::IsSubsetOf<Repetition<T>> for Class<T> {
    fn is_subset_of(&self, rep: &Repetition<T>) -> bool {
        self.iter().all(|a| a.is_subset_of(rep.element())) && rep.count().contains(1)
    }
}

impl<T: Atom> set::IsSubsetOf<Element<T>> for Class<T> {
    /// A class is always a subset of a wildcard, and never a subset of an
    /// anchor.  See the other `IsSubsetOf` implementations for `Class` for
    /// explanations of how this trait is implements for the other variants of
    /// `Element`.
    fn is_subset_of(&self, other: &Element<T>) -> bool {
        match other {
            // Anything we can do, Wildcard can do betteeeeer...
            &Element::Wildcard => true,

            &Element::Atom(a) => self.is_subset_of(&a),
            &Element::Class(ref d) => self.is_subset_of(d),
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),
            &Element::Sequence(ref seq) => self.is_subset_of(seq),
            &Element::Union(ref union) => self.is_subset_of(union),
            &Element::Repeat(ref rep) => self.is_subset_of(rep),
            &Element::Anchor(_) => false,
        }
    }
}

impl<T: Atom, U> FromIterator<U> for Class<T>
where ClassMember<T>: From<U> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item=U> {
        Class{polarity: Polarity::NORMAL, members: Vec::from_iter(iter.into_iter().map(|x| x.into()))}
    }
}

macro_rules! impl_class_from {
    ($T: ty, $from: ty) => {
        impl<'a> From<$from> for Class<$T> {
            fn from(c: $from) -> Self {
                Self::new(Polarity::NORMAL,
                          c.into_iter().map(|cr| if cr.end != cr.start { ClassMember::Range(cr.start.into(), cr.end.into()) }
                                            else { ClassMember::Atom(cr.start.into()) }))
            }
        }
    };
}

impl_class_from!(char, regex_syntax::CharClass);
impl_class_from!(u8, regex_syntax::ByteClass);
impl_class_from!(ByteOrChar, regex_syntax::CharClass);
impl_class_from!(ByteOrChar, regex_syntax::ByteClass);

// ----------------------------------------------------------------

/** Flag type used to differentiate between normal and inverting matches on
 * pattern elements. */
#[derive(Debug,Copy,Clone,PartialEq, PartialOrd, Eq, Ord)]
pub enum Polarity {
    /// Normal match behavior.
    NORMAL,
    /// Invert the match result.
    INVERTED
}
<commit_msg>pattern/class: remove unused lifetime in `From` impl-helper macro<commit_after>//! Atom-class implementation.

use std::ops::{BitXor, Sub, Range, RangeInclusive};
use std::iter::FromIterator;
use std::fmt::{self, Debug};

use regex_syntax;
use itertools::Itertools;

use super::{Anchor, Atom, ByteOrChar, Element, Repetition, Sequence, Union};
use super::{Distance, Step};
use util::set::{self, Contains};

// ----------------------------------------------------------------
// Class

/// Any member of a class of atoms
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub enum ClassMember<T: Atom> {
    /// A single atom
    Atom(T),

    /// A range of atoms
    Range(T, T)
}

impl<T: Atom> ClassMember<T> {
    /// Map the class-member's atoms to a different type
    pub fn map_atoms<U, F>(self, f: F) -> ClassMember<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        match self {
            ClassMember::Atom(a) => ClassMember::Atom(f(a)),
            ClassMember::Range(a, b) => ClassMember::Range(f(a), f(b))
        }
    }

    /// Get the number of individual atoms that this class member represents.
    pub fn len(&self) -> usize
        where T: Distance
    {
        match self {
            &ClassMember::Atom(_) => 1,
            &ClassMember::Range(first, last) => last.distance(&first) + 1,
        }
    }

    /// Fetch an iterator over each discrete value contained by this member.
    #[inline]
     pub fn iter(&self) -> impl Iterator<Item=T>
        where T: Step {
        match self {
            &ClassMember::Atom(a) => AtomIter(a...a),
            &ClassMember::Range(a, b) => AtomIter(a...b),
        }
    }
}

impl<T: Atom> set::Contains<T> for ClassMember<T> {
    /// Check if the member is or contains a particular atom.
    fn contains(&self, x: T) -> bool {
        match self {
            &ClassMember::Atom(a) => x == a,
            &ClassMember::Range(a, b) => (a...b).contains(x),
        }
    }
}

/// Iterator over the atoms specified by a class member.
struct AtomIter<T: Atom>(RangeInclusive<T>);

impl<T: Atom> Iterator for AtomIter<T>
        where T: Step
{
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        match self.0 {
            RangeInclusive::NonEmpty{start, end} => {
                let next_start = start.increment();
                if next_start > end {
                    self.0 = RangeInclusive::Empty{at: end};
                } else {
                    self.0 = RangeInclusive::NonEmpty{start: next_start, end: end};
                }
                Some(start) },
            RangeInclusive::Empty{..} => None
        }
    }
}

/*impl<T: Atom> Debug for ClassMember<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ClassMember::Atom(a) => write!(f, "{:?}", a),
            ClassMember::Range(first, last) => write!(f, "{:?}-{:?}", first, last)
        }
    }
}*/

impl<T: Atom> From<T> for ClassMember<T> {
    fn from(a: T) -> Self { ClassMember::Atom(a) }
}

impl From<regex_syntax::ClassRange> for ClassMember<ByteOrChar> {
    fn from(cr: regex_syntax::ClassRange) -> Self {
        ClassMember::Range(cr.start.into(), cr.end.into())
    }
}

impl From<regex_syntax::ByteRange> for ClassMember<ByteOrChar> {
    fn from(cr: regex_syntax::ByteRange) -> Self {
        ClassMember::Range(cr.start.into(), cr.end.into())
    }
}

impl From<regex_syntax::ClassRange> for ClassMember<char> {
    fn from(cr: regex_syntax::ClassRange) -> Self {
        ClassMember::Range(cr.start, cr.end)
    }
}

impl From<regex_syntax::ByteRange> for ClassMember<u8> {
    fn from(cr: regex_syntax::ByteRange) -> Self {
        ClassMember::Range(cr.start, cr.end)
    }
}

impl<T: Atom> From<Range<T>> for ClassMember<T>
    where T: Sub<usize,Output=T> + Sub<T,Output=usize>
{
    fn from(r: Range<T>) -> Self {
        if r.end - r.start > 1 { ClassMember::Range(r.start, r.end - 1usize) }
        else { ClassMember::Atom(r.start) }
    }
}
// ----------------------------------------------------------------

/// A set of atoms and/or ranges of atoms.
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct Class<T: Atom> {
    polarity: Polarity,
    members: Vec<ClassMember<T>>
}

// FIXME: [optimize] All operations on a Class<T>, including observer and
// predicate methods, currently require at least O(N) time.  We could probably
// improve this by changing the storage representation.
impl<T: Atom> Class<T> {
    /// Create a new Class instance with specified polarity and members taken
    /// from the given iterator.
    pub fn new<I,U>(p: Polarity, items: I) -> Self
        where I: IntoIterator<Item=U>,
              ClassMember<T>: From<U> {
        Class{polarity: p, members: Vec::from_iter(items.into_iter().map(|x| x.into()))}
    }

    /// Create a new Class instance from an iterator of ClassMember instances.
    pub fn from_members<I>(m: I) -> Self
        where I: IntoIterator<Item=ClassMember<T>>
    {
        Class{polarity: Polarity::NORMAL, members: m.into_iter().collect()}
    }

    /// Map the atoms in the class to a different atom type.
    pub fn map_atoms<U, F>(self, f: F) -> Class<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        Class::new(self.polarity, self.members.into_iter().map(|m| m.map_atoms(&f)))
    }

    /// Check whether the class would match a particular atom.
    pub fn matches(&self, x: T) -> bool {
        self.has_member(x).bitxor(self.polarity == Polarity::INVERTED)
    }

    /// Check whether a particular atom is a member of this class.
    /// Unlike `matches`, this method does not take the class's polarity
    /// into account.
    pub fn has_member(&self, x: T) -> bool {
        self.members.iter().any(|&range| range.contains(x))
    }

    /// Get the number of members (atoms) in the class.
    ///
    /// Ranges of atoms count as the number of atoms in each range.
    // FIXME: [bug] handle inverted polarity?
    pub fn len(&self) -> usize {
        self.members.iter().map(|m| m.len()).sum()
    }

    /// Get the class's polarity.
    #[inline]
    pub fn polarity(&self) -> Polarity {
        self.polarity
    }

    /// Check if the class contains zero members.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.members.is_empty()
    }

    /// Fetch an iterator over the members specified in the class.
    ///
    /// Note that if the class has inverted polarity, the atoms in these
    /// members will be those which are **not** matched by the class.
    pub fn iter_members<'a>(&'a self) -> impl Iterator<Item=&'a ClassMember<T>> {
        self.members.iter()
    }

    /// Fetch an iterator over the atoms specified in the class.
    ///
    /// Note that if the class has inverted polarity, these will be those atoms
    /// which are **not** matched by the class.
    pub fn iter<'a>(&'a self) -> impl Iterator<Item=T> + 'a {
        self.members.iter().flat_map(|m| m.iter())
    }
}

impl<T: Atom> Debug for Class<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.polarity == Polarity::NORMAL {
            write!(f, "[{}]", self.members.iter().map(|m| format!("{:?}", m)).join(","))
        } else {
            write!(f, "[^{}]", self.members.iter().map(|m| format!("{:?}", m)).join(","))
        }
    }
}

impl<'a, T: 'a + Atom> set::Contains<&'a ClassMember<T>> for Class<T> {
    fn contains(&self, cm: &'a ClassMember<T>) -> bool {
        self.iter_members().any(|m| cm == m)
    }
}
impl<T: Atom> set::Contains<T> for Class<T> {
    /// Check if any member of the class matches the given atom.
    fn contains(&self, x: T) -> bool {
        self.matches(x)
    }
}

impl<T: Atom> set::IsSubsetOf<T> for Class<T> {
    /// A class *can* be a subset of an atom -- as long as that atom is the
    /// only member of the class!
    #[inline]
    fn is_subset_of(&self, atom: &T) -> bool {
        self.contains(*atom) && self.polarity == Polarity::NORMAL && self.len() == 1
    }
}

impl<T: Atom> set::IsSubsetOf<Anchor<T>> for Class<T> {
    /// A class is never a subset of an anchor.
    #[inline(always)]
    fn is_subset_of(&self, _: &Anchor<T>) -> bool {
        false
    }
}

// FIXME [optimize] I suspect that we need some sort of specialized data
// structure or clever algorithm in order to perform this test in a time better
// than O(N·M).
impl<T: Atom> set::IsSubsetOf<Class<T>> for Class<T> {
    /// A class `A` is a subset of another class `B` if all atoms in `A` are
    /// also in `B`.
    fn is_subset_of(&self, other: &Self) -> bool {
        self.iter().all(|a| other.contains(a))
    }
}
impl<T: Atom> set::IsSubsetOf<Sequence<T>> for Class<T> {
    /// Any single-atom pattern like Class cannot match the same set of inputs
    /// as a Sequence, because a Sequence is guaranteed to contain at least
    /// two elements.
    #[inline]
    fn is_subset_of(&self, _: &Sequence<T>) -> bool {
        false
    }
}

impl<T: Atom> set::IsSubsetOf<Union<T>> for Class<T> {
    /// A class is a subset of a union if all members of the class are subsets
    /// of the union.
    fn is_subset_of(&self, union: &Union<T>) -> bool {
        self.iter().all(|a| a.is_subset_of(union))
    }
}

impl<T: Atom> set::IsSubsetOf<Repetition<T>> for Class<T> {
    fn is_subset_of(&self, rep: &Repetition<T>) -> bool {
        self.iter().all(|a| a.is_subset_of(rep.element())) && rep.count().contains(1)
    }
}

impl<T: Atom> set::IsSubsetOf<Element<T>> for Class<T> {
    /// A class is always a subset of a wildcard, and never a subset of an
    /// anchor.  See the other `IsSubsetOf` implementations for `Class` for
    /// explanations of how this trait is implements for the other variants of
    /// `Element`.
    fn is_subset_of(&self, other: &Element<T>) -> bool {
        match other {
            // Anything we can do, Wildcard can do betteeeeer...
            &Element::Wildcard => true,

            &Element::Atom(a) => self.is_subset_of(&a),
            &Element::Class(ref d) => self.is_subset_of(d),
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),
            &Element::Sequence(ref seq) => self.is_subset_of(seq),
            &Element::Union(ref union) => self.is_subset_of(union),
            &Element::Repeat(ref rep) => self.is_subset_of(rep),
            &Element::Anchor(_) => false,
        }
    }
}

impl<T: Atom, U> FromIterator<U> for Class<T>
where ClassMember<T>: From<U> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item=U> {
        Class{polarity: Polarity::NORMAL, members: Vec::from_iter(iter.into_iter().map(|x| x.into()))}
    }
}

macro_rules! impl_class_from {
    ($T: ty, $from: ty) => {
        impl From<$from> for Class<$T> {
            fn from(c: $from) -> Self {
                Self::new(Polarity::NORMAL,
                          c.into_iter().map(|cr| if cr.end != cr.start { ClassMember::Range(cr.start.into(), cr.end.into()) }
                                            else { ClassMember::Atom(cr.start.into()) }))
            }
        }
    };
}

impl_class_from!(char, regex_syntax::CharClass);
impl_class_from!(u8, regex_syntax::ByteClass);
impl_class_from!(ByteOrChar, regex_syntax::CharClass);
impl_class_from!(ByteOrChar, regex_syntax::ByteClass);

// ----------------------------------------------------------------

/** Flag type used to differentiate between normal and inverting matches on
 * pattern elements. */
#[derive(Debug,Copy,Clone,PartialEq, PartialOrd, Eq, Ord)]
pub enum Polarity {
    /// Normal match behavior.
    NORMAL,
    /// Invert the match result.
    INVERTED
}
<|endoftext|>


<commit_before>//! Getting the Git status of files and directories.

use std::path::{Path, PathBuf};
use std::sync::Mutex;

use log::*;

use crate::fs::fields as f;

/// A **Git cache** is assembled based on the user’s input arguments.
///
/// This uses vectors to avoid the overhead of hashing: it’s not worth it when the
/// expected number of Git repositories per exa invocation is 0 or 1...
pub struct GitCache {

    /// A list of discovered Git repositories and their paths.
    repos: Vec<GitRepo>,

    /// Paths that we’ve confirmed do not have Git repositories underneath them.
    misses: Vec<PathBuf>,
}

impl GitCache {
    pub fn has_anything_for(&self, index: &Path) -> bool {
        self.repos.iter().any(|e| e.has_path(index))
    }

    pub fn get(&self, index: &Path, prefix_lookup: bool) -> f::Git {
        self.repos.iter()
            .find(|e| e.has_path(index))
            .map(|repo| repo.search(index, prefix_lookup))
            .unwrap_or_default()
    }
}

use std::iter::FromIterator;
impl FromIterator<PathBuf> for GitCache {
    fn from_iter<I>(iter: I) -> Self
    where I: IntoIterator<Item=PathBuf>
    {
        let iter = iter.into_iter();
        let mut git = Self {
            repos: Vec::with_capacity(iter.size_hint().0),
            misses: Vec::new(),
        };

        for path in iter {
            if git.misses.contains(&path) {
                debug!("Skipping {:?} because it already came back Gitless", path);
            }
            else if git.repos.iter().any(|e| e.has_path(&path)) {
                debug!("Skipping {:?} because we already queried it", path);
            }
            else {
                match GitRepo::discover(path) {
                    Ok(r) => {
                        if let Some(r2) = git.repos.iter_mut().find(|e| e.has_workdir(&r.workdir)) {
                            debug!("Adding to existing repo (workdir matches with {:?})", r2.workdir);
                            r2.extra_paths.push(r.original_path);
                            continue;
                        }

                        debug!("Discovered new Git repo");
                        git.repos.push(r);
                    }
                    Err(miss) => {
                        git.misses.push(miss)
                    }
                }
            }
        }

        git
    }
}

/// A **Git repository** is one we’ve discovered somewhere on the filesystem.
pub struct GitRepo {

    /// The queryable contents of the repository: either a `git2` repo, or the
    /// cached results from when we queried it last time.
    contents: Mutex<GitContents>,

    /// The working directory of this repository.
    /// This is used to check whether two repositories are the same.
    workdir: PathBuf,

    /// The path that was originally checked to discover this repository.
    /// This is as important as the extra_paths (it gets checked first), but
    /// is separate to avoid having to deal with a non-empty Vec.
    original_path: PathBuf,

    /// Any other paths that were checked only to result in this same
    /// repository.
    extra_paths: Vec<PathBuf>,
}

/// A repository’s queried state.
enum GitContents {

    /// All the interesting Git stuff goes through this.
    Before {
        repo: git2::Repository,
    },

    /// Temporary value used in `repo_to_statuses` so we can move the
    /// repository out of the `Before` variant.
    Processing,

    /// The data we’ve extracted from the repository, but only after we’ve
    /// actually done so.
    After {
        statuses: Git,
    },
}

impl GitRepo {

    /// Searches through this repository for a path (to a file or directory,
    /// depending on the prefix-lookup flag) and returns its Git status.
    ///
    /// Actually querying the `git2` repository for the mapping of paths to
    /// Git statuses is only done once, and gets cached so we don’t need to
    /// re-query the entire repository the times after that.
    ///
    /// The temporary `Processing` enum variant is used after the `git2`
    /// repository is moved out, but before the results have been moved in!
    /// See <https://stackoverflow.com/q/45985827/3484614>
    fn search(&self, index: &Path, prefix_lookup: bool) -> f::Git {
        use std::mem::replace;

        let mut contents = self.contents.lock().unwrap();
        if let GitContents::After { ref statuses } = *contents {
            debug!("Git repo {:?} has been found in cache", &self.workdir);
            return statuses.status(index, prefix_lookup);
        }

        debug!("Querying Git repo {:?} for the first time", &self.workdir);
        let repo = replace(&mut *contents, GitContents::Processing).inner_repo();
        let statuses = repo_to_statuses(&repo, &self.workdir);
        let result = statuses.status(index, prefix_lookup);
        let _processing = replace(&mut *contents, GitContents::After { statuses });
        result
    }

    /// Whether this repository has the given working directory.
    fn has_workdir(&self, path: &Path) -> bool {
        self.workdir == path
    }

    /// Whether this repository cares about the given path at all.
    fn has_path(&self, path: &Path) -> bool {
        path.starts_with(&self.original_path) || self.extra_paths.iter().any(|e| path.starts_with(e))
    }

    /// Searches for a Git repository at any point above the given path.
    /// Returns the original buffer if none is found.
    fn discover(path: PathBuf) -> Result<Self, PathBuf> {
        info!("Searching for Git repository above {:?}", path);
        let repo = match git2::Repository::discover(&path) {
            Ok(r) => r,
            Err(e) => {
                error!("Error discovering Git repositories: {:?}", e);
                return Err(path);
            }
        };

        if let Some(workdir) = repo.workdir() {
            let workdir = workdir.to_path_buf();
            let contents = Mutex::new(GitContents::Before { repo });
            Ok(Self { contents, workdir, original_path: path, extra_paths: Vec::new() })
        }
        else {
            warn!("Repository has no workdir?");
            Err(path)
        }
    }
}

impl GitContents {
    /// Assumes that the repository hasn’t been queried, and extracts it
    /// (consuming the value) if it has. This is needed because the entire
    /// enum variant gets replaced when a repo is queried (see above).
    fn inner_repo(self) -> git2::Repository {
        if let Self::Before { repo } = self {
            repo
        }
        else {
            unreachable!("Tried to extract a non-Repository")
        }
    }
}

/// Iterates through a repository’s statuses, consuming it and returning the
/// mapping of files to their Git status.
/// We will have already used the working directory at this point, so it gets
/// passed in rather than deriving it from the `Repository` again.
fn repo_to_statuses(repo: &git2::Repository, workdir: &Path) -> Git {
    let mut statuses = Vec::new();

    info!("Getting Git statuses for repo with workdir {:?}", workdir);
    match repo.statuses(None) {
        Ok(es) => {
            for e in es.iter() {
                let path = workdir.join(Path::new(e.path().unwrap()));
                let elem = (path, e.status());
                statuses.push(elem);
            }
        }
        Err(e) => {
            error!("Error looking up Git statuses: {:?}", e);
        }
    }

    Git { statuses }
}

// The `repo.statuses` call above takes a long time. exa debug output:
//
//   20.311276  INFO:exa::fs::feature::git: Getting Git statuses for repo with workdir "/vagrant/"
//   20.799610  DEBUG:exa::output::table: Getting Git status for file "./Cargo.toml"
//
// Even inserting another logging line immediately afterwards doesn’t make it
// look any faster.

/// Container of Git statuses for all the files in this folder’s Git repository.
struct Git {
    statuses: Vec<(PathBuf, git2::Status)>,
}

impl Git {

    /// Get either the file or directory status for the given path.
    /// “Prefix lookup” means that it should report an aggregate status of all
    /// paths starting with the given prefix (in other words, a directory).
    fn status(&self, index: &Path, prefix_lookup: bool) -> f::Git {
        if prefix_lookup { self.dir_status(index) }
                    else { self.file_status(index) }
    }

    /// Get the status for the file at the given path.
    fn file_status(&self, file: &Path) -> f::Git {
        let path = reorient(file);

        self.statuses.iter()
            .find(|p| p.0.as_path() == path)
            .map(|&(_, s)| f::Git { staged: index_status(s), unstaged: working_tree_status(s) })
            .unwrap_or_default()
    }

    /// Get the combined, user-facing status of a file or directory.
    /// Statuses are aggregating (for example, a directory is considered
    /// modified if any file under it has the status modified), except
    /// for ignored which applies to files under (for example, a file is
    /// considered ignored if one of its parent directories is ignored)
    fn dir_status(&self, dir: &Path) -> f::Git {
        let path = reorient(dir);

        let s = self.statuses.iter()
            .filter(|p| if p.1 == git2::Status::IGNORED {
                path.starts_with(&p.0)
            } else {
                p.0.starts_with(&path)
            })
            .fold(git2::Status::empty(), |a, b| a | b.1);

        let staged = index_status(s);
        let unstaged = working_tree_status(s);
        f::Git { staged, unstaged }
    }
}

/// Converts a path to an absolute path based on the current directory.
/// Paths need to be absolute for them to be compared properly, otherwise
/// you’d ask a repo about “./README.md” but it only knows about
/// “/vagrant/README.md”, prefixed by the workdir.
fn reorient(path: &Path) -> PathBuf {
    use std::env::current_dir;

    // TODO: I’m not 100% on this func tbh
    let path = match current_dir() {
        Err(_)   => Path::new(".").join(&path),
        Ok(dir)  => dir.join(&path),
    };

    path.canonicalize().unwrap_or(path)
}

/// The character to display if the file has been modified, but not staged.
fn working_tree_status(status: git2::Status) -> f::GitStatus {
    match status {
        s if s.contains(git2::Status::WT_NEW)         => f::GitStatus::New,
        s if s.contains(git2::Status::WT_MODIFIED)    => f::GitStatus::Modified,
        s if s.contains(git2::Status::WT_DELETED)     => f::GitStatus::Deleted,
        s if s.contains(git2::Status::WT_RENAMED)     => f::GitStatus::Renamed,
        s if s.contains(git2::Status::WT_TYPECHANGE)  => f::GitStatus::TypeChange,
        s if s.contains(git2::Status::IGNORED)        => f::GitStatus::Ignored,
        s if s.contains(git2::Status::CONFLICTED)     => f::GitStatus::Conflicted,
        _                                             => f::GitStatus::NotModified,
    }
}

/// The character to display if the file has been modified and the change
/// has been staged.
fn index_status(status: git2::Status) -> f::GitStatus {
    match status {
        s if s.contains(git2::Status::INDEX_NEW)         => f::GitStatus::New,
        s if s.contains(git2::Status::INDEX_MODIFIED)    => f::GitStatus::Modified,
        s if s.contains(git2::Status::INDEX_DELETED)     => f::GitStatus::Deleted,
        s if s.contains(git2::Status::INDEX_RENAMED)     => f::GitStatus::Renamed,
        s if s.contains(git2::Status::INDEX_TYPECHANGE)  => f::GitStatus::TypeChange,
        _                                                => f::GitStatus::NotModified,
    }
}
<commit_msg>Fix deducing git ignored state for files too, not only directories<commit_after>//! Getting the Git status of files and directories.

use std::path::{Path, PathBuf};
use std::sync::Mutex;

use log::*;

use crate::fs::fields as f;

/// A **Git cache** is assembled based on the user’s input arguments.
///
/// This uses vectors to avoid the overhead of hashing: it’s not worth it when the
/// expected number of Git repositories per exa invocation is 0 or 1...
pub struct GitCache {

    /// A list of discovered Git repositories and their paths.
    repos: Vec<GitRepo>,

    /// Paths that we’ve confirmed do not have Git repositories underneath them.
    misses: Vec<PathBuf>,
}

impl GitCache {
    pub fn has_anything_for(&self, index: &Path) -> bool {
        self.repos.iter().any(|e| e.has_path(index))
    }

    pub fn get(&self, index: &Path, prefix_lookup: bool) -> f::Git {
        self.repos.iter()
            .find(|e| e.has_path(index))
            .map(|repo| repo.search(index, prefix_lookup))
            .unwrap_or_default()
    }
}

use std::iter::FromIterator;
impl FromIterator<PathBuf> for GitCache {
    fn from_iter<I>(iter: I) -> Self
    where I: IntoIterator<Item=PathBuf>
    {
        let iter = iter.into_iter();
        let mut git = Self {
            repos: Vec::with_capacity(iter.size_hint().0),
            misses: Vec::new(),
        };

        for path in iter {
            if git.misses.contains(&path) {
                debug!("Skipping {:?} because it already came back Gitless", path);
            }
            else if git.repos.iter().any(|e| e.has_path(&path)) {
                debug!("Skipping {:?} because we already queried it", path);
            }
            else {
                match GitRepo::discover(path) {
                    Ok(r) => {
                        if let Some(r2) = git.repos.iter_mut().find(|e| e.has_workdir(&r.workdir)) {
                            debug!("Adding to existing repo (workdir matches with {:?})", r2.workdir);
                            r2.extra_paths.push(r.original_path);
                            continue;
                        }

                        debug!("Discovered new Git repo");
                        git.repos.push(r);
                    }
                    Err(miss) => {
                        git.misses.push(miss)
                    }
                }
            }
        }

        git
    }
}

/// A **Git repository** is one we’ve discovered somewhere on the filesystem.
pub struct GitRepo {

    /// The queryable contents of the repository: either a `git2` repo, or the
    /// cached results from when we queried it last time.
    contents: Mutex<GitContents>,

    /// The working directory of this repository.
    /// This is used to check whether two repositories are the same.
    workdir: PathBuf,

    /// The path that was originally checked to discover this repository.
    /// This is as important as the extra_paths (it gets checked first), but
    /// is separate to avoid having to deal with a non-empty Vec.
    original_path: PathBuf,

    /// Any other paths that were checked only to result in this same
    /// repository.
    extra_paths: Vec<PathBuf>,
}

/// A repository’s queried state.
enum GitContents {

    /// All the interesting Git stuff goes through this.
    Before {
        repo: git2::Repository,
    },

    /// Temporary value used in `repo_to_statuses` so we can move the
    /// repository out of the `Before` variant.
    Processing,

    /// The data we’ve extracted from the repository, but only after we’ve
    /// actually done so.
    After {
        statuses: Git,
    },
}

impl GitRepo {

    /// Searches through this repository for a path (to a file or directory,
    /// depending on the prefix-lookup flag) and returns its Git status.
    ///
    /// Actually querying the `git2` repository for the mapping of paths to
    /// Git statuses is only done once, and gets cached so we don’t need to
    /// re-query the entire repository the times after that.
    ///
    /// The temporary `Processing` enum variant is used after the `git2`
    /// repository is moved out, but before the results have been moved in!
    /// See <https://stackoverflow.com/q/45985827/3484614>
    fn search(&self, index: &Path, prefix_lookup: bool) -> f::Git {
        use std::mem::replace;

        let mut contents = self.contents.lock().unwrap();
        if let GitContents::After { ref statuses } = *contents {
            debug!("Git repo {:?} has been found in cache", &self.workdir);
            return statuses.status(index, prefix_lookup);
        }

        debug!("Querying Git repo {:?} for the first time", &self.workdir);
        let repo = replace(&mut *contents, GitContents::Processing).inner_repo();
        let statuses = repo_to_statuses(&repo, &self.workdir);
        let result = statuses.status(index, prefix_lookup);
        let _processing = replace(&mut *contents, GitContents::After { statuses });
        result
    }

    /// Whether this repository has the given working directory.
    fn has_workdir(&self, path: &Path) -> bool {
        self.workdir == path
    }

    /// Whether this repository cares about the given path at all.
    fn has_path(&self, path: &Path) -> bool {
        path.starts_with(&self.original_path) || self.extra_paths.iter().any(|e| path.starts_with(e))
    }

    /// Searches for a Git repository at any point above the given path.
    /// Returns the original buffer if none is found.
    fn discover(path: PathBuf) -> Result<Self, PathBuf> {
        info!("Searching for Git repository above {:?}", path);
        let repo = match git2::Repository::discover(&path) {
            Ok(r) => r,
            Err(e) => {
                error!("Error discovering Git repositories: {:?}", e);
                return Err(path);
            }
        };

        if let Some(workdir) = repo.workdir() {
            let workdir = workdir.to_path_buf();
            let contents = Mutex::new(GitContents::Before { repo });
            Ok(Self { contents, workdir, original_path: path, extra_paths: Vec::new() })
        }
        else {
            warn!("Repository has no workdir?");
            Err(path)
        }
    }
}

impl GitContents {
    /// Assumes that the repository hasn’t been queried, and extracts it
    /// (consuming the value) if it has. This is needed because the entire
    /// enum variant gets replaced when a repo is queried (see above).
    fn inner_repo(self) -> git2::Repository {
        if let Self::Before { repo } = self {
            repo
        }
        else {
            unreachable!("Tried to extract a non-Repository")
        }
    }
}

/// Iterates through a repository’s statuses, consuming it and returning the
/// mapping of files to their Git status.
/// We will have already used the working directory at this point, so it gets
/// passed in rather than deriving it from the `Repository` again.
fn repo_to_statuses(repo: &git2::Repository, workdir: &Path) -> Git {
    let mut statuses = Vec::new();

    info!("Getting Git statuses for repo with workdir {:?}", workdir);
    match repo.statuses(None) {
        Ok(es) => {
            for e in es.iter() {
                let path = workdir.join(Path::new(e.path().unwrap()));
                let elem = (path, e.status());
                statuses.push(elem);
            }
        }
        Err(e) => {
            error!("Error looking up Git statuses: {:?}", e);
        }
    }

    Git { statuses }
}

// The `repo.statuses` call above takes a long time. exa debug output:
//
//   20.311276  INFO:exa::fs::feature::git: Getting Git statuses for repo with workdir "/vagrant/"
//   20.799610  DEBUG:exa::output::table: Getting Git status for file "./Cargo.toml"
//
// Even inserting another logging line immediately afterwards doesn’t make it
// look any faster.

/// Container of Git statuses for all the files in this folder’s Git repository.
struct Git {
    statuses: Vec<(PathBuf, git2::Status)>,
}

impl Git {

    /// Get either the file or directory status for the given path.
    /// “Prefix lookup” means that it should report an aggregate status of all
    /// paths starting with the given prefix (in other words, a directory).
    fn status(&self, index: &Path, prefix_lookup: bool) -> f::Git {
        if prefix_lookup { self.dir_status(index) }
                    else { self.file_status(index) }
    }

    /// Get the user-facing status of a file.
    /// We check the statuses directly applying to a file, and for the ignored
    /// status we check if any of its parents directories is ignored by git.
    fn file_status(&self, file: &Path) -> f::Git {
        let path = reorient(file);

        let s = self.statuses.iter()
            .filter(|p| if p.1 == git2::Status::IGNORED {
                path.starts_with(&p.0)
            } else {
                p.0 == path
            })
            .fold(git2::Status::empty(), |a, b| a | b.1);

        let staged = index_status(s);
        let unstaged = working_tree_status(s);
        f::Git { staged, unstaged }
    }

    /// Get the combined, user-facing status of a directory.
    /// Statuses are aggregating (for example, a directory is considered
    /// modified if any file under it has the status modified), except for
    /// ignored status which applies to files under (for example, a directory
    /// is considered ignored if one of its parent directories is ignored).
    fn dir_status(&self, dir: &Path) -> f::Git {
        let path = reorient(dir);

        let s = self.statuses.iter()
            .filter(|p| if p.1 == git2::Status::IGNORED {
                path.starts_with(&p.0)
            } else {
                p.0.starts_with(&path)
            })
            .fold(git2::Status::empty(), |a, b| a | b.1);

        let staged = index_status(s);
        let unstaged = working_tree_status(s);
        f::Git { staged, unstaged }
    }
}

/// Converts a path to an absolute path based on the current directory.
/// Paths need to be absolute for them to be compared properly, otherwise
/// you’d ask a repo about “./README.md” but it only knows about
/// “/vagrant/README.md”, prefixed by the workdir.
fn reorient(path: &Path) -> PathBuf {
    use std::env::current_dir;

    // TODO: I’m not 100% on this func tbh
    let path = match current_dir() {
        Err(_)   => Path::new(".").join(&path),
        Ok(dir)  => dir.join(&path),
    };

    path.canonicalize().unwrap_or(path)
}

/// The character to display if the file has been modified, but not staged.
fn working_tree_status(status: git2::Status) -> f::GitStatus {
    match status {
        s if s.contains(git2::Status::WT_NEW)         => f::GitStatus::New,
        s if s.contains(git2::Status::WT_MODIFIED)    => f::GitStatus::Modified,
        s if s.contains(git2::Status::WT_DELETED)     => f::GitStatus::Deleted,
        s if s.contains(git2::Status::WT_RENAMED)     => f::GitStatus::Renamed,
        s if s.contains(git2::Status::WT_TYPECHANGE)  => f::GitStatus::TypeChange,
        s if s.contains(git2::Status::IGNORED)        => f::GitStatus::Ignored,
        s if s.contains(git2::Status::CONFLICTED)     => f::GitStatus::Conflicted,
        _                                             => f::GitStatus::NotModified,
    }
}

/// The character to display if the file has been modified and the change
/// has been staged.
fn index_status(status: git2::Status) -> f::GitStatus {
    match status {
        s if s.contains(git2::Status::INDEX_NEW)         => f::GitStatus::New,
        s if s.contains(git2::Status::INDEX_MODIFIED)    => f::GitStatus::Modified,
        s if s.contains(git2::Status::INDEX_DELETED)     => f::GitStatus::Deleted,
        s if s.contains(git2::Status::INDEX_RENAMED)     => f::GitStatus::Renamed,
        s if s.contains(git2::Status::INDEX_TYPECHANGE)  => f::GitStatus::TypeChange,
        _                                                => f::GitStatus::NotModified,
    }
}
<|endoftext|>


<commit_before>use std::net::{
    IpAddr,
    Ipv4Addr,
    Ipv6Addr,
};
use c_ares;
use futures;
use futures::Future;

use error::Error;
use host::HostResults;
use resolver::{
    Options,
    Resolver,
};

/// The type of future returned by methods on the `FutureResolver`.
pub struct CAresFuture<T> {
    inner: futures::sync::oneshot::Receiver<Result<T, c_ares::Error>>,
}

impl<T> CAresFuture<T> {
    fn new(p: futures::sync::oneshot::Receiver<Result<T, c_ares::Error>>) -> Self {
        CAresFuture {
            inner: p,
        }
    }
}

impl<T> Future for CAresFuture<T> {
    type Item = T;
    type Error = c_ares::Error;

    fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
        match self.inner.poll() {
            Ok(futures::Async::NotReady) => Ok(futures::Async::NotReady),
            Err(_) => Err(c_ares::Error::ECANCELLED),
            Ok(futures::Async::Ready(res)) => {
                match res {
                    Ok(r) => Ok(futures::Async::Ready(r)),
                    Err(e) => Err(e),
                }
            }
        }
    }
}

/// An asynchronous DNS resolver, which returns results as
/// `futures::Future`s.
pub struct FutureResolver {
    inner: Resolver,
}

impl FutureResolver {
    /// Create a new `FutureResolver`, using default `Options`.
    pub fn new() -> Result<FutureResolver, Error> {
        let options = Options::default();
        Self::with_options(options)
    }

    /// Create a new `FutureResolver`, with the given `Options`.
    pub fn with_options(options: Options) -> Result<FutureResolver, Error> {
        let inner = Resolver::with_options(options)?;
        let resolver = FutureResolver {
            inner: inner,
        };
        Ok(resolver)
    }

    /// Set the list of servers to contact, instead of the servers specified
    /// in resolv.conf or the local named.
    ///
    /// String format is `host[:port]`.  IPv6 addresses with ports require
    /// square brackets eg `[2001:4860:4860::8888]:53`.
    pub fn set_servers(
        &mut self,
        servers: &[&str]) -> Result<&mut Self, c_ares::Error> {
        self.inner.set_servers(servers)?;
        Ok(self)
    }

    /// Set the local IPv4 address from which to make queries.
    pub fn set_local_ipv4(&mut self, ipv4: &Ipv4Addr) -> &mut Self {
        self.inner.set_local_ipv4(ipv4);
        self
    }

    /// Set the local IPv6 address from which to make queries.
    pub fn set_local_ipv6(&mut self, ipv6: &Ipv6Addr) -> &mut Self {
        self.inner.set_local_ipv6(ipv6);
        self
    }

    /// Set the local device from which to make queries.
    pub fn set_local_device(&mut self, device: &str) -> &mut Self {
        self.inner.set_local_device(device);
        self
    }

    /// Look up the A records associated with `name`.
    pub fn query_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_a(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the A records associated with `name`.
    pub fn search_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_a(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the AAAA records associated with `name`.
    pub fn query_aaaa(&self, name: &str)  -> CAresFuture<c_ares::AAAAResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_aaaa(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the AAAA records associated with `name`.
    pub fn search_aaaa(&self, name: &str) -> CAresFuture<c_ares::AAAAResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_aaaa(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the CNAME records associated with `name`.
    pub fn query_cname(&self, name: &str)
        -> CAresFuture<c_ares::CNameResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_cname(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the CNAME records associated with `name`.
    pub fn search_cname(&self, name: &str)
        -> CAresFuture<c_ares::CNameResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_cname(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the MX records associated with `name`.
    pub fn query_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_mx(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the MX records associated with `name`.
    pub fn search_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_mx(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the NAPTR records associated with `name`.
    pub fn query_naptr(&self, name: &str)
        -> CAresFuture<c_ares::NAPTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_naptr(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the NAPTR records associated with `name`.
    pub fn search_naptr(&self, name: &str)
        -> CAresFuture<c_ares::NAPTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_naptr(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the NS records associated with `name`.
    pub fn query_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_ns(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the NS records associated with `name`.
    pub fn search_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_ns(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the PTR records associated with `name`.
    pub fn query_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_ptr(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the PTR records associated with `name`.
    pub fn search_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_ptr(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the SOA records associated with `name`.
    pub fn query_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
        let (c, p) = futures::oneshot();
        self.inner.query_soa(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the SOA records associated with `name`.
    pub fn search_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
        let (c, p) = futures::oneshot();
        self.inner.search_soa(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the SRV records associated with `name`.
    pub fn query_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_srv(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the SRV records associated with `name`.
    pub fn search_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_srv(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the TXT records associated with `name`.
    pub fn query_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_txt(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the TXT records associated with `name`.
    pub fn search_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_txt(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Perform a host query by address.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_host_by_address(&self, address: &IpAddr)
        -> CAresFuture<HostResults> {
        let (c, p) = futures::oneshot();
        self.inner.get_host_by_address(address, move |result| {
            let _ = c.send(result.map(|h| h.into()));
        });
        CAresFuture::new(p)
    }

    /// Perform a host query by name.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_host_by_name(&self, name: &str, family: c_ares::AddressFamily)
        -> CAresFuture<HostResults> {
        let (c, p) = futures::oneshot();
        self.inner.get_host_by_name(name, family, move |result| {
            let _ = c.send(result.map(|h| h.into()));
        });
        CAresFuture::new(p)
    }

    /// Initiate a single-question DNS query for `name`.  The class and type of
    /// the query are per the provided parameters, taking values as defined in
    /// `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    ///
    /// This method is provided so that users can query DNS types for which
    /// `c-ares` does not provide a parser; or in case a third-party parser is
    /// preferred.  Usually, if a suitable `query_xxx()` is available, that
    /// should be used.
    pub fn query(&self, name: &str, dns_class: u16, query_type: u16)
        -> CAresFuture<Vec<u8>> {
        let (c, p) = futures::oneshot();
        self.inner.query(name, dns_class, query_type, move |result| {
            let _ = c.send(result.map(|h| h.to_owned()));
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Initiate a series of single-question DNS queries for `name`.  The
    /// class and type of the query are per the provided parameters, taking
    /// values as defined in `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    ///
    /// This method is provided so that users can query DNS types for which
    /// `c-ares` does not provide a parser; or in case a third-party parser is
    /// preferred.  Usually, if a suitable `query_xxx()` is available, that
    /// should be used.
    pub fn search(&self, name: &str, dns_class: u16, query_type: u16)
        -> CAresFuture<Vec<u8>> {
        let (c, p) = futures::oneshot();
        self.inner.search(name, dns_class, query_type, move |result| {
            let _ = c.send(result.map(|h| h.to_owned()));
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Cancel all requests made on this `FutureResolver`.
    pub fn cancel(&mut self) {
        self.inner.cancel()
    }
}
<commit_msg>use the new CAresFuture struct for search and query functions<commit_after>use std::net::{
    IpAddr,
    Ipv4Addr,
    Ipv6Addr,
};
use c_ares;
use futures;
use futures::Future;

use error::Error;
use host::HostResults;
use resolver::{
    Options,
    Resolver,
};

/// The type of future returned by methods on the `FutureResolver`.
pub struct CAresFuture<T> {
    inner: futures::sync::oneshot::Receiver<Result<T, c_ares::Error>>,
}

impl<T> CAresFuture<T> {
    fn new(p: futures::sync::oneshot::Receiver<Result<T, c_ares::Error>>) -> Self {
        CAresFuture {
            inner: p,
        }
    }
}

impl<T> Future for CAresFuture<T> {
    type Item = T;
    type Error = c_ares::Error;

    fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
        match self.inner.poll() {
            Ok(futures::Async::NotReady) => Ok(futures::Async::NotReady),
            Err(_) => Err(c_ares::Error::ECANCELLED),
            Ok(futures::Async::Ready(res)) => {
                match res {
                    Ok(r) => Ok(futures::Async::Ready(r)),
                    Err(e) => Err(e),
                }
            }
        }
    }
}

/// An asynchronous DNS resolver, which returns results as
/// `futures::Future`s.
pub struct FutureResolver {
    inner: Resolver,
}

impl FutureResolver {
    /// Create a new `FutureResolver`, using default `Options`.
    pub fn new() -> Result<FutureResolver, Error> {
        let options = Options::default();
        Self::with_options(options)
    }

    /// Create a new `FutureResolver`, with the given `Options`.
    pub fn with_options(options: Options) -> Result<FutureResolver, Error> {
        let inner = Resolver::with_options(options)?;
        let resolver = FutureResolver {
            inner: inner,
        };
        Ok(resolver)
    }

    /// Set the list of servers to contact, instead of the servers specified
    /// in resolv.conf or the local named.
    ///
    /// String format is `host[:port]`.  IPv6 addresses with ports require
    /// square brackets eg `[2001:4860:4860::8888]:53`.
    pub fn set_servers(
        &mut self,
        servers: &[&str]) -> Result<&mut Self, c_ares::Error> {
        self.inner.set_servers(servers)?;
        Ok(self)
    }

    /// Set the local IPv4 address from which to make queries.
    pub fn set_local_ipv4(&mut self, ipv4: &Ipv4Addr) -> &mut Self {
        self.inner.set_local_ipv4(ipv4);
        self
    }

    /// Set the local IPv6 address from which to make queries.
    pub fn set_local_ipv6(&mut self, ipv6: &Ipv6Addr) -> &mut Self {
        self.inner.set_local_ipv6(ipv6);
        self
    }

    /// Set the local device from which to make queries.
    pub fn set_local_device(&mut self, device: &str) -> &mut Self {
        self.inner.set_local_device(device);
        self
    }

    /// Look up the A records associated with `name`.
    pub fn query_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_a(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the A records associated with `name`.
    pub fn search_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_a(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the AAAA records associated with `name`.
    pub fn query_aaaa(&self, name: &str)  -> CAresFuture<c_ares::AAAAResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_aaaa(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the AAAA records associated with `name`.
    pub fn search_aaaa(&self, name: &str) -> CAresFuture<c_ares::AAAAResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_aaaa(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the CNAME records associated with `name`.
    pub fn query_cname(&self, name: &str)
        -> CAresFuture<c_ares::CNameResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_cname(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the CNAME records associated with `name`.
    pub fn search_cname(&self, name: &str)
        -> CAresFuture<c_ares::CNameResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_cname(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the MX records associated with `name`.
    pub fn query_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_mx(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the MX records associated with `name`.
    pub fn search_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_mx(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the NAPTR records associated with `name`.
    pub fn query_naptr(&self, name: &str)
        -> CAresFuture<c_ares::NAPTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_naptr(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the NAPTR records associated with `name`.
    pub fn search_naptr(&self, name: &str)
        -> CAresFuture<c_ares::NAPTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_naptr(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the NS records associated with `name`.
    pub fn query_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_ns(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the NS records associated with `name`.
    pub fn search_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_ns(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the PTR records associated with `name`.
    pub fn query_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_ptr(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the PTR records associated with `name`.
    pub fn search_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_ptr(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the SOA records associated with `name`.
    pub fn query_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
        let (c, p) = futures::oneshot();
        self.inner.query_soa(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the SOA records associated with `name`.
    pub fn search_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
        let (c, p) = futures::oneshot();
        self.inner.search_soa(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the SRV records associated with `name`.
    pub fn query_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_srv(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the SRV records associated with `name`.
    pub fn search_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_srv(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Look up the TXT records associated with `name`.
    pub fn query_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_txt(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Search for the TXT records associated with `name`.
    pub fn search_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_txt(name, move |result| {
            let _ = c.send(result);
        });
        CAresFuture::new(p)
    }

    /// Perform a host query by address.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_host_by_address(&self, address: &IpAddr)
        -> CAresFuture<HostResults> {
        let (c, p) = futures::oneshot();
        self.inner.get_host_by_address(address, move |result| {
            let _ = c.send(result.map(|h| h.into()));
        });
        CAresFuture::new(p)
    }

    /// Perform a host query by name.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_host_by_name(&self, name: &str, family: c_ares::AddressFamily)
        -> CAresFuture<HostResults> {
        let (c, p) = futures::oneshot();
        self.inner.get_host_by_name(name, family, move |result| {
            let _ = c.send(result.map(|h| h.into()));
        });
        CAresFuture::new(p)
    }

    /// Initiate a single-question DNS query for `name`.  The class and type of
    /// the query are per the provided parameters, taking values as defined in
    /// `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    ///
    /// This method is provided so that users can query DNS types for which
    /// `c-ares` does not provide a parser; or in case a third-party parser is
    /// preferred.  Usually, if a suitable `query_xxx()` is available, that
    /// should be used.
    pub fn query(&self, name: &str, dns_class: u16, query_type: u16)
        -> CAresFuture<Vec<u8>> {
        let (c, p) = futures::oneshot();
        self.inner.query(name, dns_class, query_type, move |result| {
            let _ = c.send(result.map(|h| h.to_owned()));
        });
        CAresFuture::new(p)
    }

    /// Initiate a series of single-question DNS queries for `name`.  The
    /// class and type of the query are per the provided parameters, taking
    /// values as defined in `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    ///
    /// This method is provided so that users can query DNS types for which
    /// `c-ares` does not provide a parser; or in case a third-party parser is
    /// preferred.  Usually, if a suitable `query_xxx()` is available, that
    /// should be used.
    pub fn search(&self, name: &str, dns_class: u16, query_type: u16)
        -> CAresFuture<Vec<u8>> {
        let (c, p) = futures::oneshot();
        self.inner.search(name, dns_class, query_type, move |result| {
            let _ = c.send(result.map(|h| h.to_owned()));
        });
        CAresFuture::new(p)
    }

    /// Cancel all requests made on this `FutureResolver`.
    pub fn cancel(&mut self) {
        self.inner.cancel()
    }
}
<|endoftext|>


<commit_before>use std::i64;

use super::number::NumberOps;
use super::point::Point;
use super::ring::Ring;

pub const HALF_MAX_ERR: i64  = i64::MAX / 2;

#[inline]
pub fn h_multi_intersect(p1: Point, p2: Point, step_y: i64, inters: &mut Ring<i64>) {
   let start = 1 + p1.y / step_y;
   let end = 1 + (p2.y - 1) / step_y;

   for i in start..end {
      let x = h_intersect(p1, p2, i * step_y);
      inters.push(x);
   }
}

#[inline]
pub fn h_multi_intersect_fast(p1: Point, p2: Point, step_y: i64, inters: &mut Ring<i64>) {
   let start = 1 + p1.y / step_y;
   let end = 1 + (p2.y - 1) / step_y;

   let dy = p2.y - p1.y;
   let dx = p2.x - p1.x;
   let dx_signum = dx.signum();

   let step_x = dx * step_y / dy;

   let max_div_dy = i64::MAX / dy;

   let err_step = max_div_dy * (step_y * dx.abs() - step_x * dy);

   let fdy = start * step_y - p1.y;
   let fdx = dx * fdy / dy;

   let mut x = p1.x + fdx;

   if err_step == 0 {
      for _ in start..end {
         inters.push(x);

         x += step_x;
      }

      return;
   }

   let mut err = max_div_dy * (fdy * dx.abs() - fdx * dy) - HALF_MAX_ERR;

   for _ in start..end {
      if err > 0 {
         x += dx_signum;
         err -= i64::MAX;
      }

      inters.push(x);

      x += step_x;

      err += err_step;
   }
}

#[inline]
fn h_intersect(p1: Point, p2: Point, y: i64) -> i64 {
   p1.x + ((p2.x - p1.x) * (y - p1.y)).rounding_div(p2.y - p1.y)
}

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

   use super::super::point::Point;
   use super::super::ring::Ring;

   use super::*;

   #[test]
   fn test_correct() {
      let mut inters = Ring::new(100_000);
      let mut inters_fast = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      h_multi_intersect(p1, p2, 1000, &mut inters);
      h_multi_intersect_fast(p1, p2, 1000, &mut inters_fast);

      for (correct, fast) in inters[..].iter().zip(inters_fast[..].iter()) {
         assert_eq!(correct, fast);
      }
   }

   #[bench]
   fn bench_lineinter(b: &mut Bencher) {
      let mut inters = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      b.iter(|| {
         for _ in 0..1000 {
            inters.clear();
            h_multi_intersect(p1, p2, 1000, &mut inters);
         }
      });
   }

   #[bench]
   fn bench_lineinter_fast(b: &mut Bencher) {
      let mut inters = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      b.iter(|| {
         for _ in 0..1000 {
            inters.clear();
            h_multi_intersect_fast(p1, p2, 1000, &mut inters);
         }
      });
   }
}
<commit_msg>V intersection version of the fast multiple intersection algorithm<commit_after>use std::i64;

use super::number::NumberOps;
use super::point::Point;
use super::ring::Ring;

pub const HALF_MAX_ERR: i64  = i64::MAX / 2;

#[inline]
pub fn h_multi_intersect(p1: Point, p2: Point, step_y: i64, inters: &mut Ring<i64>) {
   let start = 1 + p1.y / step_y;
   let end = 1 + (p2.y - 1) / step_y;

   for i in start..end {
      let x = h_intersect(p1, p2, i * step_y);
      inters.push(x);
   }
}

#[inline]
pub fn v_multi_intersect(p1: Point, p2: Point, step_x: i64, inters: &mut Ring<i64>) {
   let start = 1 + p1.x / step_x;
   let end = 1 + (p2.x - 1) / step_x;

   for i in start..end {
      let y = v_intersect(p1, p2, i * step_x);
      inters.push(y);
   }
}

#[inline]
pub fn h_multi_intersect_fast(p1: Point, p2: Point, step_y: i64, inters: &mut Ring<i64>) -> i64 {
   let start = 1 + p1.y / step_y;
   let end = 1 + (p2.y - 1) / step_y;

   let dy = p2.y - p1.y;
   let dx = p2.x - p1.x;
   let dx_signum = dx.signum();

   let step_x = dx * step_y / dy;

   let max_div_dy = i64::MAX / dy;

   let err_step = max_div_dy * (step_y * dx * dx_signum - step_x * dy);

   let first_y = start * step_y;

   let fdy = first_y - p1.y;
   let fdx = dx * fdy / dy;

   let mut x = p1.x + fdx;

   if err_step == 0 {
      for _ in start..end {
         inters.push(x);

         x += step_x;
      }

      return first_y;
   }

   let mut err = max_div_dy * (fdy * dx * dx_signum - fdx * dy) - HALF_MAX_ERR;

   for _ in start..end {
      if err > 0 {
         x += dx_signum;
         err -= i64::MAX;
      }

      inters.push(x);

      x += step_x;

      err += err_step;
   }

   first_y
}

#[inline]
pub fn v_multi_intersect_fast(p1: Point, p2: Point, step_x: i64, inters: &mut Ring<i64>) -> i64 {
   let start = 1 + p1.x / step_x;
   let end = 1 + (p2.x - 1) / step_x;

   let dx = p2.x - p1.x;
   let dy = p2.y - p1.y;
   let dy_signum = dy.signum();

   let step_y = dy * step_x / dx;

   let max_div_dx = i64::MAX / dx;

   let err_step = max_div_dx * (step_x * dy * dy_signum - step_y * dx);

   let first_x = start * step_x;

   let fdx = first_x - p1.x;
   let fdy = dy * fdx / dx;

   let mut y = p1.y + fdy;

   if err_step == 0 {
      for _ in start..end {
         inters.push(y);

         y += step_y;
      }

      return first_x;
   }

   let mut err = max_div_dx * (fdx * dy * dy_signum - fdy * dx) - HALF_MAX_ERR;

   for _ in start..end {
      if err > 0 {
         y += dy_signum;
         err -= i64::MAX;
      }

      inters.push(y);

      y += step_y;

      err += err_step;
   }

   first_x
}

#[inline]
fn h_intersect(p1: Point, p2: Point, y: i64) -> i64 {
   p1.x + ((p2.x - p1.x) * (y - p1.y)).rounding_div(p2.y - p1.y)
}

#[inline]
fn v_intersect(p1: Point, p2: Point, x: i64) -> i64 {
   p1.y + ((p2.y - p1.y) * (x - p1.x)).rounding_div(p2.x - p1.x)
}

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

   use super::super::point::Point;
   use super::super::ring::Ring;

   use super::*;

   #[test]
   fn test_correct_h() {
      let mut inters = Ring::new(100_000);
      let mut inters_fast = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      h_multi_intersect(p1, p2, 1000, &mut inters);
      h_multi_intersect_fast(p1, p2, 1000, &mut inters_fast);

      for (correct, fast) in inters[..].iter().zip(inters_fast[..].iter()) {
         assert_eq!(correct, fast);
      }
   }

   #[test]
   fn test_correct_v() {
      let mut inters = Ring::new(100_000);
      let mut inters_fast = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      v_multi_intersect(p1, p2, 1000, &mut inters);
      v_multi_intersect_fast(p1, p2, 1000, &mut inters_fast);

      for (correct, fast) in inters[..].iter().zip(inters_fast[..].iter()) {
         assert_eq!(correct, fast);
      }
   }

   #[bench]
   fn bench_lineinter(b: &mut Bencher) {
      let mut inters = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      b.iter(|| {
         for _ in 0..1000 {
            inters.clear();
            h_multi_intersect(p1, p2, 1000, &mut inters);
         }
      });
   }

   #[bench]
   fn bench_lineinter_fast(b: &mut Bencher) {
      let mut inters = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      b.iter(|| {
         for _ in 0..1000 {
            inters.clear();
            h_multi_intersect_fast(p1, p2, 1000, &mut inters);
         }
      });
   }
}
<|endoftext|>


<commit_before>use std::io::Read;
use hilbert_curve::BytewiseCached;
use typedrw::TypedMemoryMap;

pub trait EdgeMapper {
    fn map_edges<F: FnMut(u32, u32)>(&self, action: F);
}

pub struct DeltaCompressedReaderMapper<R: Read, F: Fn()->R> {
    reader: F,
}

impl<R: Read, F: Fn()->R> DeltaCompressedReaderMapper<R, F> {
    pub fn new(reader: F) -> DeltaCompressedReaderMapper<R, F> {
        DeltaCompressedReaderMapper {
            reader: reader,
        }
    }
}

impl<R: Read, F: Fn()->R> EdgeMapper for DeltaCompressedReaderMapper<R, F> {
    fn map_edges<A: FnMut(u32, u32)>(&self, mut action: A) {

        let mut hilbert = BytewiseCached::new();
        let mut current = 0u64;
        let mut reader = (self.reader)();

        let mut delta = 0u64;    // for accumulating a delta
        let mut depth = 0u8;     // for counting number of zeros

        let mut buffer = vec![0u8; 1 << 16];
        while let Ok(read) = reader.read(&mut buffer[..]) {
            if read == 0 {
                // Reached EOF.
                break;
            }
            for &byte in &buffer[..read] {
                if byte == 0 && delta == 0 {
                    depth += 1;
                }
                else {
                    delta = (delta << 8) + (byte as u64);
                    if depth == 0 {
                        current += delta;
                        delta = 0;
                        let (x,y) = hilbert.detangle(current);
                        action(x,y);
                    }
                    else {
                        depth -= 1;
                    }
                }
            }
        }
    }
}

pub struct DeltaCompressedSliceMapper<'a> {
    slice: &'a [u8],
}

impl<'a> DeltaCompressedSliceMapper<'a> {
    pub fn new(slice: &'a [u8]) -> DeltaCompressedSliceMapper<'a> {
        DeltaCompressedSliceMapper {
            slice: slice,
        }
    }
}

impl<'a> EdgeMapper for DeltaCompressedSliceMapper<'a> {
    fn map_edges<A: FnMut(u32, u32)>(&self, mut action: A) {

        let mut hilbert = BytewiseCached::new();
        let mut current = 0u64;

        let mut cursor = 0;
        while cursor < self.slice.len() {
            let byte = unsafe { *self.slice.get_unchecked(cursor) };
            cursor += 1;

            if byte > 0 {
                current += byte as u64;
                let (x,y) = hilbert.detangle(current);
                action(x,y);
            }
            else {
                let mut depth = 2;
                while unsafe { *self.slice.get_unchecked(cursor) } == 0 {
                    cursor += 1;
                    depth += 1;
                }
                let mut delta = 0u64;
                while depth > 0 {
                    delta = (delta << 8) + (unsafe { *self.slice.get_unchecked(cursor) } as u64);
                    cursor += 1;
                    depth -= 1;
                }

                current += delta;
                let (x,y) = hilbert.detangle(current);
                action(x,y);
            }
        }
    }
}

// // naughty method using unsafe transmute to read a filled binary buffer as a typed buffer
// fn read_as_typed<'a, R: Read, T: Copy>(reader: &mut R, buffer: &'a mut[u8]) -> Result<&'a[T]> {
//     if mem::size_of::<T>() * (buffer.len() / mem::size_of::<T>()) < buffer.len() {
//         panic!("buffer size must be a multiple of mem::size_of::<T>() = {:?}", mem::size_of::<T>());
//     }
//
//     let mut read = try!(reader.read(buffer));
//     while mem::size_of::<T>() * (read / mem::size_of::<T>()) < read {
//         read += try!(reader.read(&mut buffer[read..]));
//     }
//
//     Ok(unsafe { mem::transmute(RawSlice {
//         data: buffer.as_mut_ptr() as *const T,
//         len:  read / mem::size_of::<T>(),
//     }) })
// }

// pub struct UpperLowerMapper<R1: Read, R2: Read, F1: Fn()->R1, F2: Fn()->R2> {
//     pub upper: F1,
//     pub lower: F2,
// }
//
// impl<R1: Read, R2: Read, F1: Fn()->R1, F2: Fn()->R2> EdgeMapper for UpperLowerMapper<R1, R2, F1, F2> {
//     fn map_edges<F: FnMut(u32, u32) -> ()>(&self, mut action: F) -> () {
//         let mut upper_reader = (self.upper)();
//         let mut lower_reader = (self.lower)();
//         let mut upper_buffer = vec![0u8; 1 << 20];
//         let mut lower_buffer = vec![0u8; 1 << 20];
//         while let Ok(upper) = read_as_typed::<_,((u16,u16),u32)>(&mut upper_reader, &mut upper_buffer[..]) {
//             for &((ux, uy), mut count) in upper {
//                 let ux = (ux as u32) << 16;
//                 let uy = (uy as u32) << 16;
//                 while count > 0 {
//                     let size = min(lower_buffer.len(), 4 * count as usize);
//                     if let Ok(lower) = read_as_typed::<_,(u16,u16)>(&mut lower_reader, &mut lower_buffer[..size]) {
//                         for &(lx, ly) in lower {
//                             action(ux + lx as u32, uy + ly as u32);
//                         }
//                         count -= lower.len() as u32;
//                     }
//                 }
//             }
//         }
//     }
// }

// pub struct NodesEdgesMapper<R1: Read, R2: Read, F1: Fn()->R1, F2: Fn()->R2> {
//     pub nodes: F1,
//     pub edges: F2,
// }
//
// impl<R1: Read, R2: Read, F1: Fn()->R1, F2: Fn()->R2> EdgeMapper for NodesEdgesMapper<R1, R2, F1, F2> {
//     fn map_edges<F: FnMut(u32, u32) -> ()>(&self, mut action: F) -> () {
//         let mut nodes_reader = (self.nodes)();
//         let mut edges_reader = (self.edges)();
//         let mut nodes_buffer = vec![0u8; 1 << 20];
//         let mut edges_buffer = vec![0u8; 1 << 20];
//         while let Ok(nodes) = read_as_typed::<_,(u32,u32)>(&mut nodes_reader, &mut nodes_buffer[..]) {
//             for &(source, mut count) in nodes {
//                 while count > 0 {
//                     let size = min(edges_buffer.len(), 4 * count as usize);
//                     if let Ok(edges) = read_as_typed::<_,u32>(&mut edges_reader, &mut edges_buffer[..size]) {
//                         for &target in edges {
//                             action(source, target);
//                         }
//                         count -= edges.len() as u32;
//                     }
//                 }
//             }
//         }
//     }
// }

pub struct UpperLowerMemMapper {
    upper:  TypedMemoryMap<((u16,u16), u32)>,
    lower:  TypedMemoryMap<(u16, u16)>,
}

impl UpperLowerMemMapper {
    pub fn new(graph_name: &str) -> UpperLowerMemMapper {
        UpperLowerMemMapper {
            upper: TypedMemoryMap::new(format!("{}.upper", graph_name)),
            lower: TypedMemoryMap::new(format!("{}.lower", graph_name)),
        }
    }
}

impl EdgeMapper for UpperLowerMemMapper {
    fn map_edges<F: FnMut(u32, u32)>(&self, mut action: F) {
        let mut slice = &self.lower[..];
        for &((u16_x, u16_y), count) in &self.upper[..] {
            let u16_x = (u16_x as u32) << 16;
            let u16_y = (u16_y as u32) << 16;
            for &(l16_x, l16_y) in &slice[.. count as usize] {
                action(u16_x | l16_x as u32, u16_y | l16_y as u32);
            }

            slice = &slice[count as usize ..];
        }
    }
}

pub struct NodesEdgesMemMapper {
    nodes:  TypedMemoryMap<(u32, u32)>,
    edges:  TypedMemoryMap<u32>,
}

impl NodesEdgesMemMapper {
    pub fn new(graph_name: &str) -> NodesEdgesMemMapper {
        NodesEdgesMemMapper {
            nodes: TypedMemoryMap::new(format!("{}.nodes", graph_name)),
            edges: TypedMemoryMap::new(format!("{}.edges", graph_name)),
        }
    }
}

impl EdgeMapper for NodesEdgesMemMapper {
    fn map_edges<F: FnMut(u32, u32)>(&self, mut action: F) {
        let mut slice = &self.edges[..];
        for &(node, count) in &self.nodes[..] {
            for &edge in &slice[.. count as usize] {
                action(node, edge);
            }

            slice = &slice[count as usize ..];
        }
    }
}

// use std::fs::File;
// use byteorder::{WriteBytesExt, LittleEndian};

pub struct ReaderMapper<B: ::std::io::BufRead, F: Fn() -> B> {
    pub reader: F,
}

impl<R: ::std::io::BufRead, RF: Fn() -> R> EdgeMapper for ReaderMapper<R, RF> {
    fn map_edges<F: FnMut(u32, u32) -> ()>(&self, mut action: F) -> () {
        let reader = (self.reader)();
        for readline in reader.lines() {
            let line = readline.ok().expect("read error");
            if !line.starts_with('#') {
                let mut elts = line[..].split_whitespace();
                let src: u32 = elts.next().unwrap().parse().ok().expect("malformed src");
                let dst: u32 = elts.next().unwrap().parse().ok().expect("malformed dst");
                action(src, dst);
            }
        }
    }
}<commit_msg>try out impl trait<commit_after>use std::io::Read;
use hilbert_curve::BytewiseCached;
use typedrw::TypedMemoryMap;

pub trait EdgeMapper {
    fn map_edges(&self, action: impl FnMut(u32, u32));
}

pub struct DeltaCompressedReaderMapper<R: Read, F: Fn()->R> {
    reader: F,
}

impl<R: Read, F: Fn()->R> DeltaCompressedReaderMapper<R, F> {
    pub fn new(reader: F) -> DeltaCompressedReaderMapper<R, F> {
        DeltaCompressedReaderMapper {
            reader: reader,
        }
    }
}

impl<R: Read, F: Fn()->R> EdgeMapper for DeltaCompressedReaderMapper<R, F> {
    fn map_edges(&self, mut action: impl FnMut(u32, u32)) {

        let mut hilbert = BytewiseCached::new();
        let mut current = 0u64;
        let mut reader = (self.reader)();

        let mut delta = 0u64;    // for accumulating a delta
        let mut depth = 0u8;     // for counting number of zeros

        let mut buffer = vec![0u8; 1 << 16];
        while let Ok(read) = reader.read(&mut buffer[..]) {
            if read == 0 {
                // Reached EOF.
                break;
            }
            for &byte in &buffer[..read] {
                if byte == 0 && delta == 0 {
                    depth += 1;
                }
                else {
                    delta = (delta << 8) + (byte as u64);
                    if depth == 0 {
                        current += delta;
                        delta = 0;
                        let (x,y) = hilbert.detangle(current);
                        action(x,y);
                    }
                    else {
                        depth -= 1;
                    }
                }
            }
        }
    }
}

pub struct DeltaCompressedSliceMapper<'a> {
    slice: &'a [u8],
}

impl<'a> DeltaCompressedSliceMapper<'a> {
    pub fn new(slice: &'a [u8]) -> DeltaCompressedSliceMapper<'a> {
        DeltaCompressedSliceMapper {
            slice: slice,
        }
    }
}

impl<'a> EdgeMapper for DeltaCompressedSliceMapper<'a> {
    fn map_edges(&self, mut action: impl FnMut(u32, u32)) {

        let mut hilbert = BytewiseCached::new();
        let mut current = 0u64;

        let mut cursor = 0;
        while cursor < self.slice.len() {
            let byte = unsafe { *self.slice.get_unchecked(cursor) };
            cursor += 1;

            if byte > 0 {
                current += byte as u64;
                let (x,y) = hilbert.detangle(current);
                action(x,y);
            }
            else {
                let mut depth = 2;
                while unsafe { *self.slice.get_unchecked(cursor) } == 0 {
                    cursor += 1;
                    depth += 1;
                }
                let mut delta = 0u64;
                while depth > 0 {
                    delta = (delta << 8) + (unsafe { *self.slice.get_unchecked(cursor) } as u64);
                    cursor += 1;
                    depth -= 1;
                }

                current += delta;
                let (x,y) = hilbert.detangle(current);
                action(x,y);
            }
        }
    }
}

// // naughty method using unsafe transmute to read a filled binary buffer as a typed buffer
// fn read_as_typed<'a, R: Read, T: Copy>(reader: &mut R, buffer: &'a mut[u8]) -> Result<&'a[T]> {
//     if mem::size_of::<T>() * (buffer.len() / mem::size_of::<T>()) < buffer.len() {
//         panic!("buffer size must be a multiple of mem::size_of::<T>() = {:?}", mem::size_of::<T>());
//     }
//
//     let mut read = try!(reader.read(buffer));
//     while mem::size_of::<T>() * (read / mem::size_of::<T>()) < read {
//         read += try!(reader.read(&mut buffer[read..]));
//     }
//
//     Ok(unsafe { mem::transmute(RawSlice {
//         data: buffer.as_mut_ptr() as *const T,
//         len:  read / mem::size_of::<T>(),
//     }) })
// }

// pub struct UpperLowerMapper<R1: Read, R2: Read, F1: Fn()->R1, F2: Fn()->R2> {
//     pub upper: F1,
//     pub lower: F2,
// }
//
// impl<R1: Read, R2: Read, F1: Fn()->R1, F2: Fn()->R2> EdgeMapper for UpperLowerMapper<R1, R2, F1, F2> {
//     fn map_edges<F: FnMut(u32, u32) -> ()>(&self, mut action: F) -> () {
//         let mut upper_reader = (self.upper)();
//         let mut lower_reader = (self.lower)();
//         let mut upper_buffer = vec![0u8; 1 << 20];
//         let mut lower_buffer = vec![0u8; 1 << 20];
//         while let Ok(upper) = read_as_typed::<_,((u16,u16),u32)>(&mut upper_reader, &mut upper_buffer[..]) {
//             for &((ux, uy), mut count) in upper {
//                 let ux = (ux as u32) << 16;
//                 let uy = (uy as u32) << 16;
//                 while count > 0 {
//                     let size = min(lower_buffer.len(), 4 * count as usize);
//                     if let Ok(lower) = read_as_typed::<_,(u16,u16)>(&mut lower_reader, &mut lower_buffer[..size]) {
//                         for &(lx, ly) in lower {
//                             action(ux + lx as u32, uy + ly as u32);
//                         }
//                         count -= lower.len() as u32;
//                     }
//                 }
//             }
//         }
//     }
// }

// pub struct NodesEdgesMapper<R1: Read, R2: Read, F1: Fn()->R1, F2: Fn()->R2> {
//     pub nodes: F1,
//     pub edges: F2,
// }
//
// impl<R1: Read, R2: Read, F1: Fn()->R1, F2: Fn()->R2> EdgeMapper for NodesEdgesMapper<R1, R2, F1, F2> {
//     fn map_edges<F: FnMut(u32, u32) -> ()>(&self, mut action: F) -> () {
//         let mut nodes_reader = (self.nodes)();
//         let mut edges_reader = (self.edges)();
//         let mut nodes_buffer = vec![0u8; 1 << 20];
//         let mut edges_buffer = vec![0u8; 1 << 20];
//         while let Ok(nodes) = read_as_typed::<_,(u32,u32)>(&mut nodes_reader, &mut nodes_buffer[..]) {
//             for &(source, mut count) in nodes {
//                 while count > 0 {
//                     let size = min(edges_buffer.len(), 4 * count as usize);
//                     if let Ok(edges) = read_as_typed::<_,u32>(&mut edges_reader, &mut edges_buffer[..size]) {
//                         for &target in edges {
//                             action(source, target);
//                         }
//                         count -= edges.len() as u32;
//                     }
//                 }
//             }
//         }
//     }
// }

pub struct UpperLowerMemMapper {
    upper:  TypedMemoryMap<((u16,u16), u32)>,
    lower:  TypedMemoryMap<(u16, u16)>,
}

impl UpperLowerMemMapper {
    pub fn new(graph_name: &str) -> UpperLowerMemMapper {
        UpperLowerMemMapper {
            upper: TypedMemoryMap::new(format!("{}.upper", graph_name)),
            lower: TypedMemoryMap::new(format!("{}.lower", graph_name)),
        }
    }
}

impl EdgeMapper for UpperLowerMemMapper {
    fn map_edges(&self, mut action: impl FnMut(u32, u32)) {
        let mut slice = &self.lower[..];
        for &((u16_x, u16_y), count) in &self.upper[..] {
            let u16_x = (u16_x as u32) << 16;
            let u16_y = (u16_y as u32) << 16;
            for &(l16_x, l16_y) in &slice[.. count as usize] {
                action(u16_x | l16_x as u32, u16_y | l16_y as u32);
            }

            slice = &slice[count as usize ..];
        }
    }
}

pub struct NodesEdgesMemMapper {
    nodes:  TypedMemoryMap<(u32, u32)>,
    edges:  TypedMemoryMap<u32>,
}

impl NodesEdgesMemMapper {
    pub fn new(graph_name: &str) -> NodesEdgesMemMapper {
        NodesEdgesMemMapper {
            nodes: TypedMemoryMap::new(format!("{}.nodes", graph_name)),
            edges: TypedMemoryMap::new(format!("{}.edges", graph_name)),
        }
    }
}

impl EdgeMapper for NodesEdgesMemMapper {
    fn map_edges(&self, mut action: impl FnMut(u32, u32)) {
        let mut slice = &self.edges[..];
        for &(node, count) in &self.nodes[..] {
            for &edge in &slice[.. count as usize] {
                action(node, edge);
            }

            slice = &slice[count as usize ..];
        }
    }
}

pub struct ReaderMapper<B: ::std::io::BufRead, F: Fn() -> B> {
    pub reader: F,
}

impl<R: ::std::io::BufRead, RF: Fn() -> R> EdgeMapper for ReaderMapper<R, RF> {
    fn map_edges(&self, mut action: impl FnMut(u32, u32)) {
        let reader = (self.reader)();
        for readline in reader.lines() {
            let line = readline.ok().expect("read error");
            if !line.starts_with('#') {
                let mut elts = line[..].split_whitespace();
                let src: u32 = elts.next().unwrap().parse().ok().expect("malformed src");
                let dst: u32 = elts.next().unwrap().parse().ok().expect("malformed dst");
                action(src, dst);
            }
        }
    }
}<|endoftext|>