<commit_before>use std::marker::PhantomData;
use std::mem;
use std::slice::from_raw_parts;

use crate::SV;
use crate::convert::{FromSV, TryFromSV};
use crate::handle::Owned;
use crate::raw;

/// Perl hash object.
pub struct HV(Owned<raw::HV>);

impl HV {
    fn pthx(&self) -> raw::Interpreter {
        self.0.pthx()
    }
    fn as_ptr(&self) -> *mut raw::HV {
        self.0.as_ptr()
    }

    method! {
        /// Frees the all the elements of a hash, leaving it empty.
        ///
        /// See [`hv_clear`](http://perldoc.perl.org/perlapi.html#hv_clear).
        simple fn clear() = hv_clear()
    }

    method! {
        /// Clears any placeholders from a hash.
        ///
        /// See [`hv_clear_placeholders`](http://perldoc.perl.org/perlapi.html#hv_clear_placeholders).
        simple fn clear_placeholders() = hv_clear_placeholders()
    }

    method! {
        /// Deletes a key/value pair in the hash. The value's SV is removed from the hash, made
        /// mortal, and returned to the caller.
        ///
        /// See [`hv_delete`](http://perldoc.perl.org/perlapi.html#hv_delete).
        getter fn delete(key: &str) = hv_delete(key.as_ptr() as *const _, -(key.len() as raw::I32), 0)
    }

    method! {
        /// Deletes a key/value pair in the hash. The value's SV is removed from the hash, made
        /// mortal, and returned to the caller.
        ///
        /// See [`hv_delete`](http://perldoc.perl.org/perlapi.html#hv_delete).
        simple fn discard(key: &str) = hv_delete(key.as_ptr() as *const _, -(key.len() as raw::I32), raw::G_DISCARD as raw::I32)
    }

    method! {
        /// Returns a boolean indicating whether the specified hash key
        /// exists.
        ///
        /// See [`hv_exists`](http://perldoc.perl.org/perlapi.html#hv_exists).
        simple fn exists(key: &str) -> bool = hv_exists(key.as_ptr() as *const _, -(key.len() as raw::I32)) != 0
    }

    method! {
        /// Returns the SV which corresponds to the specified key in the hash.
        ///
        /// See [`hv_fetch`](http://perldoc.perl.org/perlapi.html#hv_fetch).
        getptr fn fetch(key: &str) = hv_fetch(key.as_ptr() as *const _, -(key.len() as raw::I32), 0)
    }

    method! {
        /// Returns the SV which corresponds to the specified key in the hash. Stores new SV in the
        /// hash and returns it if key was not part of the hash.
        ///
        /// See [`hv_fetch`](http://perldoc.perl.org/perlapi.html#hv_fetch).
        getptr fn fetch_lvalue(key: &str) = hv_fetch(key.as_ptr() as *const _, -(key.len() as raw::I32), 1)
    }

    /// Stores an SV in a hash.
    ///
    /// See [`hv_store`](http://perldoc.perl.org/perlapi.html#hv_store).
    #[inline]
    pub fn store(&self, key: &str, val: SV) {
        unsafe {
            let raw = val.into_raw();
            let svpp = self.pthx().hv_store(
                self.as_ptr(),
                key.as_ptr() as *const _,
                -(key.len() as raw::I32),
                raw,
                0,
            );
            if svpp.is_null() {
                self.pthx().ouroboros_sv_refcnt_dec(raw)
            }
        }
    }

    /// Construct new HV from a raw pointer without incrementing reference counter (raw pointer
    /// already "owns" one incref).
    #[inline]
    pub unsafe fn from_raw_owned(pthx: raw::Interpreter, raw: *mut raw::HV) -> HV {
        HV(Owned::from_raw_owned(pthx, raw))
    }

    /// Construct new HV from a raw pointer and increment its reference counter (raw pointer is
    /// "borrowed" from another structure that owns one incref).
    #[inline]
    pub unsafe fn from_raw_borrowed(pthx: raw::Interpreter, raw: *mut raw::HV) -> HV {
        HV(Owned::from_raw_borrowed(pthx, raw))
    }

    /// Get an iterator over the hash.
    #[inline]
    pub fn iter<T: FromSV>(&self) -> Iter<T> {
        Iter::new(self)
    }

    /// Get an iterator over the hash values.
    #[inline]
    pub fn values<T: FromSV>(&self) -> Values<T> {
        Values::new(self)
    }

    /// Get an iterator over the hash keys.
    #[inline]
    pub fn keys(&self) -> Keys {
        Keys::new(self)
    }
}

impl TryFromSV for HV {
    type Error = &'static str;

    unsafe fn try_from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> Result<HV, Self::Error> {
        if pthx.ouroboros_sv_rok(raw) == 0 {
            return Err("not a hash reference");
        }

        Ok(HV::from_raw_borrowed(
            pthx,
            pthx.ouroboros_sv_rv(raw) as *mut _,
        ))
    }
}

pub struct Iter<'a, T> {
    hv: &'a HV,
    ty: PhantomData<T>,
}

impl<'a, T> Iter<'a, T> {
    fn new(hv: &'a HV) -> Self {
        unsafe { hv.pthx().hv_iterinit(hv.as_ptr()) };
        Iter {
            hv: hv,
            ty: PhantomData,
        }
    }
}

impl<'a, T: FromSV> Iterator for Iter<'a, T> {
    type Item = (&'a [u8], T);

    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            let pthx = self.hv.pthx();
            let hv_ptr = self.hv.as_ptr();

            let he = pthx.hv_iternext(hv_ptr);
            if he.is_null() {
                None
            } else {
                let mut klen: raw::I32 = mem::uninitialized();
                let k_ptr = pthx.hv_iterkey(he, &mut klen as *mut _) as *const u8;
                let k = from_raw_parts(k_ptr, klen as usize);
                let v = pthx.hv_iterval(hv_ptr, he);
                Some((k, T::from_sv(pthx, v)))
            }
        }
    }
}

pub struct Values<'a, T> {
    hv: &'a HV,
    ty: PhantomData<T>,
}

impl<'a, T> Values<'a, T> {
    fn new(hv: &'a HV) -> Self {
        unsafe { hv.pthx().hv_iterinit(hv.as_ptr()) };
        Values {
            hv: hv,
            ty: PhantomData,
        }
    }
}

impl<'a, T: FromSV> Iterator for Values<'a, T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            let pthx = self.hv.pthx();
            let hv_ptr = self.hv.as_ptr();

            let he = pthx.hv_iternext(hv_ptr);
            if he.is_null() {
                None
            } else {
                let v = pthx.hv_iterval(hv_ptr, he);
                Some(T::from_sv(pthx, v))
            }
        }
    }
}

pub struct Keys<'a>(&'a HV);

impl<'a> Keys<'a> {
    fn new(hv: &'a HV) -> Self {
        unsafe { hv.pthx().hv_iterinit(hv.as_ptr()) };
        Keys(hv)
    }
}

impl<'a> Iterator for Keys<'a> {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            let pthx = self.0.pthx();
            let hv_ptr = self.0.as_ptr();

            let he = pthx.hv_iternext(hv_ptr);
            if he.is_null() {
                None
            } else {
                let mut klen: raw::I32 = mem::uninitialized();
                let k_ptr = pthx.hv_iterkey(he, &mut klen as *mut _) as *const u8;
                let k = from_raw_parts(k_ptr, klen as usize);
                Some(k)
            }
        }
    }
}

impl<'a> IntoIterator for &'a HV {
    type Item = (&'a [u8], SV);
    type IntoIter = Iter<'a, SV>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}
<commit_msg>refactor: use hv_iternextsv<commit_after>use std::marker::PhantomData;
use std::mem;
use std::slice::from_raw_parts;

use crate::SV;
use crate::convert::{FromSV, TryFromSV};
use crate::handle::Owned;
use crate::raw;

/// Perl hash object.
pub struct HV(Owned<raw::HV>);

impl HV {
    fn pthx(&self) -> raw::Interpreter {
        self.0.pthx()
    }
    fn as_ptr(&self) -> *mut raw::HV {
        self.0.as_ptr()
    }

    method! {
        /// Frees the all the elements of a hash, leaving it empty.
        ///
        /// See [`hv_clear`](http://perldoc.perl.org/perlapi.html#hv_clear).
        simple fn clear() = hv_clear()
    }

    method! {
        /// Clears any placeholders from a hash.
        ///
        /// See [`hv_clear_placeholders`](http://perldoc.perl.org/perlapi.html#hv_clear_placeholders).
        simple fn clear_placeholders() = hv_clear_placeholders()
    }

    method! {
        /// Deletes a key/value pair in the hash. The value's SV is removed from the hash, made
        /// mortal, and returned to the caller.
        ///
        /// See [`hv_delete`](http://perldoc.perl.org/perlapi.html#hv_delete).
        getter fn delete(key: &str) = hv_delete(key.as_ptr() as *const _, -(key.len() as raw::I32), 0)
    }

    method! {
        /// Deletes a key/value pair in the hash. The value's SV is removed from the hash, made
        /// mortal, and returned to the caller.
        ///
        /// See [`hv_delete`](http://perldoc.perl.org/perlapi.html#hv_delete).
        simple fn discard(key: &str) = hv_delete(key.as_ptr() as *const _, -(key.len() as raw::I32), raw::G_DISCARD as raw::I32)
    }

    method! {
        /// Returns a boolean indicating whether the specified hash key
        /// exists.
        ///
        /// See [`hv_exists`](http://perldoc.perl.org/perlapi.html#hv_exists).
        simple fn exists(key: &str) -> bool = hv_exists(key.as_ptr() as *const _, -(key.len() as raw::I32)) != 0
    }

    method! {
        /// Returns the SV which corresponds to the specified key in the hash.
        ///
        /// See [`hv_fetch`](http://perldoc.perl.org/perlapi.html#hv_fetch).
        getptr fn fetch(key: &str) = hv_fetch(key.as_ptr() as *const _, -(key.len() as raw::I32), 0)
    }

    method! {
        /// Returns the SV which corresponds to the specified key in the hash. Stores new SV in the
        /// hash and returns it if key was not part of the hash.
        ///
        /// See [`hv_fetch`](http://perldoc.perl.org/perlapi.html#hv_fetch).
        getptr fn fetch_lvalue(key: &str) = hv_fetch(key.as_ptr() as *const _, -(key.len() as raw::I32), 1)
    }

    /// Stores an SV in a hash.
    ///
    /// See [`hv_store`](http://perldoc.perl.org/perlapi.html#hv_store).
    #[inline]
    pub fn store(&self, key: &str, val: SV) {
        unsafe {
            let raw = val.into_raw();
            let svpp = self.pthx().hv_store(
                self.as_ptr(),
                key.as_ptr() as *const _,
                -(key.len() as raw::I32),
                raw,
                0,
            );
            if svpp.is_null() {
                self.pthx().ouroboros_sv_refcnt_dec(raw)
            }
        }
    }

    /// Construct new HV from a raw pointer without incrementing reference counter (raw pointer
    /// already "owns" one incref).
    #[inline]
    pub unsafe fn from_raw_owned(pthx: raw::Interpreter, raw: *mut raw::HV) -> HV {
        HV(Owned::from_raw_owned(pthx, raw))
    }

    /// Construct new HV from a raw pointer and increment its reference counter (raw pointer is
    /// "borrowed" from another structure that owns one incref).
    #[inline]
    pub unsafe fn from_raw_borrowed(pthx: raw::Interpreter, raw: *mut raw::HV) -> HV {
        HV(Owned::from_raw_borrowed(pthx, raw))
    }

    /// Get an iterator over the hash.
    #[inline]
    pub fn iter<T: FromSV>(&self) -> Iter<T> {
        Iter::new(self)
    }

    /// Get an iterator over the hash values.
    #[inline]
    pub fn values<T: FromSV>(&self) -> Values<T> {
        Values::new(self)
    }

    /// Get an iterator over the hash keys.
    #[inline]
    pub fn keys(&self) -> Keys {
        Keys::new(self)
    }
}

impl TryFromSV for HV {
    type Error = &'static str;

    unsafe fn try_from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> Result<HV, Self::Error> {
        if pthx.ouroboros_sv_rok(raw) == 0 {
            return Err("not a hash reference");
        }

        Ok(HV::from_raw_borrowed(
            pthx,
            pthx.ouroboros_sv_rv(raw) as *mut _,
        ))
    }
}

pub struct Iter<'a, T> {
    hv: &'a HV,
    ty: PhantomData<T>,
}

impl<'a, T> Iter<'a, T> {
    fn new(hv: &'a HV) -> Self {
        unsafe { hv.pthx().hv_iterinit(hv.as_ptr()) };
        Iter {
            hv: hv,
            ty: PhantomData,
        }
    }
}

impl<'a, T: FromSV> Iterator for Iter<'a, T> {
    type Item = (&'a [u8], T);

    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            let pthx = self.hv.pthx();
            let hv_ptr = self.hv.as_ptr();

            let mut k_ptr: *mut i8 = mem::uninitialized();
            let mut klen: raw::I32 = mem::uninitialized();
            let v = pthx.hv_iternextsv(
                hv_ptr,
                &mut k_ptr as *mut _,
                &mut klen as *mut _,
            );
            if v.is_null() {
                None
            } else {
                let k = from_raw_parts(k_ptr as *const u8, klen as usize);
                Some((k, T::from_sv(pthx, v)))
            }
        }
    }
}

pub struct Values<'a, T> {
    hv: &'a HV,
    ty: PhantomData<T>,
}

impl<'a, T> Values<'a, T> {
    fn new(hv: &'a HV) -> Self {
        unsafe { hv.pthx().hv_iterinit(hv.as_ptr()) };
        Values {
            hv: hv,
            ty: PhantomData,
        }
    }
}

impl<'a, T: FromSV> Iterator for Values<'a, T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            let pthx = self.hv.pthx();
            let hv_ptr = self.hv.as_ptr();

            let he = pthx.hv_iternext(hv_ptr);
            if he.is_null() {
                None
            } else {
                let v = pthx.hv_iterval(hv_ptr, he);
                Some(T::from_sv(pthx, v))
            }
        }
    }
}

pub struct Keys<'a>(&'a HV);

impl<'a> Keys<'a> {
    fn new(hv: &'a HV) -> Self {
        unsafe { hv.pthx().hv_iterinit(hv.as_ptr()) };
        Keys(hv)
    }
}

impl<'a> Iterator for Keys<'a> {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            let pthx = self.0.pthx();
            let hv_ptr = self.0.as_ptr();

            let he = pthx.hv_iternext(hv_ptr);
            if he.is_null() {
                None
            } else {
                let mut klen: raw::I32 = mem::uninitialized();
                let k_ptr = pthx.hv_iterkey(he, &mut klen as *mut _) as *const u8;
                let k = from_raw_parts(k_ptr, klen as usize);
                Some(k)
            }
        }
    }
}

impl<'a> IntoIterator for &'a HV {
    type Item = (&'a [u8], SV);
    type IntoIter = Iter<'a, SV>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};

use structs::{Point, Prism};
use traits::{HasValues, HasWalls};

/// Find the points in a line between the current point and the one provided
///
/// # Example
///
/// ```
/// use std::collections::HashSet;
///
/// use hex_math::{line, Point};
///
/// let point: Point = Point::new(1, 2, 5);
/// let other: Point = Point::new(3, 4, 10);
/// let set: HashSet<Point> = line(&point, &other);
///
/// assert!(set.contains(&Point::new(1, 2, 5)));
/// assert!(set.contains(&Point::new(2, 2, 6)));
/// assert!(set.contains(&Point::new(2, 3, 8)));
/// assert!(set.contains(&Point::new(3, 3, 9)));
/// assert!(set.contains(&Point::new(3, 4, 10)));
/// assert_eq!(set.len(), 5);
/// ```
pub fn line<T: HasValues>(
  point: &T,
  other: &T
) -> HashSet<Point> {
  util::line(point, other, None, None::<&HashMap<Point, Prism>>)
}

/// Find the points within range in a line through two points
///
/// # Example
///
/// ```
/// use std::collections::HashSet;
///
/// use hex_math::{line_through, Point};
///
/// let point: Point = Point::new(1, 2, 5);
/// let other: Point = Point::new(2, 2, 6);
/// let set: HashSet<Point> = line_through(&point, &other, 3);
///
/// assert!(set.contains(&Point::new(1, 2, 5)));
/// assert!(set.contains(&Point::new(2, 2, 6)));
/// assert!(set.contains(&Point::new(3, 2, 7)));
/// assert!(set.contains(&Point::new(4, 2, 8)));
/// assert_eq!(set.len(), 4);
/// ```
pub fn line_through<T: HasValues>(
  point: &T,
  other: &T,
  range: i32,
) -> HashSet<Point> {
  util::line(point, other, Some(range), None::<&HashMap<Point, Prism>>)
}

/// Find unblocked points in a line between two points
///
/// # Example
///
/// ```
/// use std::collections::{HashSet, HashMap};
///
/// use hex_math::{HasValues, ray, Point, Prism};
///
/// let point: Point = Point::new(1, 2, 5);
/// let other: Point = Point::new(3, 4, 10);
/// let mut map: HashMap<Point, Prism> = HashMap::new();
///
/// let wall: Point = Point::new(3, 4, 10);
/// let prism: Prism = Prism::new(Point::from(wall.values()), 0, 0, 0, 1);
///
/// map.insert(wall, prism);
///
/// let set: HashSet<Point> = ray(&point, &other, &map);
///
/// assert!(set.contains(&Point::new(1, 2, 5)));
/// assert!(set.contains(&Point::new(2, 2, 6)));
/// assert!(set.contains(&Point::new(2, 3, 8)));
/// assert!(set.contains(&Point::new(3, 3, 9)));
/// assert_eq!(set.len(), 4);
/// ```
pub fn ray<T: HasValues, U: HasWalls>(
  point: &T,
  other: &T,
  map: &HashMap<Point, U>,
) -> HashSet<Point> {
  util::line(point, other, None, Some(map))
}

/// Find unblocked points within range in a line through two points
///
/// # Example
///
/// ```
/// use std::collections::{HashSet, HashMap};
///
/// use hex_math::{HasValues, ray_through, Point, Prism};
///
/// let point: Point = Point::new(1, 2, 5);
/// let other: Point = Point::new(2, 2, 6);
/// let mut map: HashMap<Point, Prism> = HashMap::new();
///
/// let wall: Point = Point::new(4, 2, 8);
/// let prism: Prism = Prism::new(Point::from(wall.values()), 0, 0, 0, 1);
///
/// map.insert(wall, prism);
///
/// let set: HashSet<Point> = ray_through(&point, &other, 3, &map);
///
/// assert!(set.contains(&Point::new(1, 2, 5)));
/// assert!(set.contains(&Point::new(2, 2, 6)));
/// assert!(set.contains(&Point::new(3, 2, 7)));
/// assert_eq!(set.len(), 3);
/// ```
pub fn ray_through<T: HasValues, U: HasWalls>(
  point: &T,
  other: &T,
  range: i32,
  map: &HashMap<Point, U>,
) -> HashSet<Point> {
  util::line(point, other, Some(range), Some(map))
}

mod util {
  use std::collections::{HashSet, HashMap};

  use distance::{distance, distance_2d};
  use enums::Direction;
  use structs::{FloatPoint, Point};
  use traits::{HasValues, HasWalls};

  /// Return the floats one step along a line between two points
  ///
  /// The lerp is offset a small amount to prevent points from landing
  /// directly on the line between two hexes.
  pub fn step_size<T: HasValues>(a: &T, b: &T, step: f32) -> FloatPoint {

    let lerp = |x: i32, y: i32| 1e-6 + (y - x) as f32 * step;
    let (qa, ra, ta) = a.values();
    let (qb, rb, tb) = b.values();

    let result = FloatPoint::new(
      lerp(qa, qb),
      lerp(ra, rb),
      lerp(ta, tb),
    );

    result

  }

  /// Return the direction of one point which is one step after the other
  pub fn get_step_direction(point: &Point, other: &Point) -> Direction {

    let diff: Point = other - point;
    let (dq, dr, dt) = diff.values();

    match dt.signum() {
       1 => return Direction::Up,
      -1 => return Direction::Down,
       _ => (),
    }

    return match (dq.signum(), dr.signum()) {
      ( 1,  0) => Direction::East,
      ( 0,  1) => Direction::Southeast,
      (-1,  1) => Direction::Southwest,
      (-1,  0) => Direction::West,
      ( 0, -1) => Direction::Northwest,
      ( 1, -1) => Direction::Northeast,
      _ => panic!(),
    }

  }

  /// Find the points in a line between two points
  ///
  /// Optionally provide a range. The line will end at that range.
  ///
  /// Optionally provide a map with walls which are impassable.
  pub fn line<T: HasValues, U: HasWalls>(
    point: &T,
    other: &T,
    range: Option<i32>,
    map: Option<&HashMap<Point, U>>,
  ) -> HashSet<Point> {

    let mut set: HashSet<Point> = HashSet::new();

    set.insert(Point::from(point.values()));

    if point.values() == other.values() {
      return set;
    }

    let distance: i32 = if point.values_2d() == other.values_2d() {
      distance(point, other)
    } else {
      distance_2d(point, other)
    };

    let empty: HashMap<Point, U> = HashMap::new();
    let map: &HashMap<Point, U> = map.unwrap_or(&empty);

    let step: f32 = 1f32 / distance as f32;
    let size: FloatPoint = step_size(point, other, step);

    let mut found: FloatPoint = FloatPoint::from(point.values());
    let mut last: Point = Point::from(point.values());

    let has_wall = |point: &Point, dir: &Direction| match map.get(point) {
      Some(prism) => prism.has_wall(dir),
      None => false,
    };

    for _ in 0..range.unwrap_or(distance) {

      found = &found + &size;

      let round: Point = found.round();
      let direction: Direction = get_step_direction(&last, &round);

      let break_before_enter = has_wall(&last, &direction)
        || has_wall(&round, &direction.opposite());

      if break_before_enter {
        break;
      }

      last = Point::from(round.values());

      set.insert(round);

    }

    set

  }

}

#[cfg(test)]
mod tests {
  use std::collections::{HashSet, HashMap};

  use enums::Direction;
  use structs::{Point, Prism};
  use structs::FloatPoint;
  use traits::HasValues;

  use super::util;

  #[test]
  fn step_size() {
    let point: Point = Point::new(1, 2, 5);
    let other: Point = Point::new(1, 12, 5);
    let size: FloatPoint = util::step_size(&point, &other, 1f32);

    assert_eq!((1e-6, 10f32 + 1e-6, 1e-6), size.values());
  }

  #[test]
  fn line_vertical() {
    let point: Point = Point::new(1, 2, 5);
    let other: Point = Point::new(1, 2, 7);

    let line: HashSet<Point> = util::line(
      &point,
      &other,
      None,
      None::<&HashMap<Point, Prism>>
    );

    assert!(line.contains(&Point::new(1, 2, 5)));
    assert!(line.contains(&Point::new(1, 2, 6)));
    assert!(line.contains(&Point::new(1, 2, 7)));
    assert_eq!(line.len(), 3);
  }

  #[test]
  fn get_step_direction() {

    let point:     Point = Point::new(1, 2, 5);
    let east:      Point = Point::new(2, 2, 5);
    let southeast: Point = Point::new(1, 3, 5);
    let southwest: Point = Point::new(0, 3, 5);
    let west:      Point = Point::new(0, 2, 5);
    let northwest: Point = Point::new(1, 1, 5);
    let northeast: Point = Point::new(2, 1, 5);
    let up:        Point = Point::new(1, 2, 6);
    let down:      Point = Point::new(1, 2, 4);

    let get = util::get_step_direction;

    assert_eq!(Direction::East,      get(&point, &east));
    assert_eq!(Direction::Southeast, get(&point, &southeast));
    assert_eq!(Direction::Southwest, get(&point, &southwest));
    assert_eq!(Direction::West,      get(&point, &west));
    assert_eq!(Direction::Northwest, get(&point, &northwest));
    assert_eq!(Direction::Northeast, get(&point, &northeast));
    assert_eq!(Direction::Up,        get(&point, &up));
    assert_eq!(Direction::Down,      get(&point, &down));

  }

}

<commit_msg>Issue #60: wip vertical line steps<commit_after>use std::collections::{HashMap, HashSet};

use structs::{Point, Prism};
use traits::{HasValues, HasWalls};

/// Find the points in a line between the current point and the one provided
///
/// # Example
///
/// ```
/// use std::collections::HashSet;
///
/// use hex_math::{line, Point};
///
/// let point: Point = Point::new(1, 2, 5);
/// let other: Point = Point::new(3, 4, 10);
/// let set: HashSet<Point> = line(&point, &other);
///
/// assert!(set.contains(&Point::new(1, 2, 5)));
/// assert!(set.contains(&Point::new(2, 2, 6)));
/// assert!(set.contains(&Point::new(2, 3, 8)));
/// assert!(set.contains(&Point::new(3, 3, 9)));
/// assert!(set.contains(&Point::new(3, 4, 10)));
/// assert_eq!(set.len(), 5);
/// ```
pub fn line<T: HasValues>(
  point: &T,
  other: &T
) -> HashSet<Point> {
  util::line(point, other, None, None::<&HashMap<Point, Prism>>)
}

/// Find the points within range in a line through two points
///
/// # Example
///
/// ```
/// use std::collections::HashSet;
///
/// use hex_math::{line_through, Point};
///
/// let point: Point = Point::new(1, 2, 5);
/// let other: Point = Point::new(2, 2, 6);
/// let set: HashSet<Point> = line_through(&point, &other, 3);
///
/// assert!(set.contains(&Point::new(1, 2, 5)));
/// assert!(set.contains(&Point::new(2, 2, 6)));
/// assert!(set.contains(&Point::new(3, 2, 7)));
/// assert!(set.contains(&Point::new(4, 2, 8)));
/// assert_eq!(set.len(), 4);
/// ```
pub fn line_through<T: HasValues>(
  point: &T,
  other: &T,
  range: i32,
) -> HashSet<Point> {
  util::line(point, other, Some(range), None::<&HashMap<Point, Prism>>)
}

/// Find unblocked points in a line between two points
///
/// # Example
///
/// ```
/// use std::collections::{HashSet, HashMap};
///
/// use hex_math::{HasValues, ray, Point, Prism};
///
/// let point: Point = Point::new(1, 2, 5);
/// let other: Point = Point::new(3, 4, 10);
/// let mut map: HashMap<Point, Prism> = HashMap::new();
///
/// let wall: Point = Point::new(3, 4, 10);
/// let prism: Prism = Prism::new(Point::from(wall.values()), 0, 0, 0, 1);
///
/// map.insert(wall, prism);
///
/// let set: HashSet<Point> = ray(&point, &other, &map);
///
/// assert!(set.contains(&Point::new(1, 2, 5)));
/// assert!(set.contains(&Point::new(2, 2, 6)));
/// assert!(set.contains(&Point::new(2, 3, 8)));
/// assert!(set.contains(&Point::new(3, 3, 9)));
/// assert_eq!(set.len(), 4);
/// ```
pub fn ray<T: HasValues, U: HasWalls>(
  point: &T,
  other: &T,
  map: &HashMap<Point, U>,
) -> HashSet<Point> {
  util::line(point, other, None, Some(map))
}

/// Find unblocked points within range in a line through two points
///
/// # Example
///
/// ```
/// use std::collections::{HashSet, HashMap};
///
/// use hex_math::{HasValues, ray_through, Point, Prism};
///
/// let point: Point = Point::new(1, 2, 5);
/// let other: Point = Point::new(2, 2, 6);
/// let mut map: HashMap<Point, Prism> = HashMap::new();
///
/// let wall: Point = Point::new(4, 2, 8);
/// let prism: Prism = Prism::new(Point::from(wall.values()), 0, 0, 0, 1);
///
/// map.insert(wall, prism);
///
/// let set: HashSet<Point> = ray_through(&point, &other, 3, &map);
///
/// assert!(set.contains(&Point::new(1, 2, 5)));
/// assert!(set.contains(&Point::new(2, 2, 6)));
/// assert!(set.contains(&Point::new(3, 2, 7)));
/// assert_eq!(set.len(), 3);
/// ```
pub fn ray_through<T: HasValues, U: HasWalls>(
  point: &T,
  other: &T,
  range: i32,
  map: &HashMap<Point, U>,
) -> HashSet<Point> {
  util::line(point, other, Some(range), Some(map))
}

mod util {
  use std::collections::{HashSet, HashMap};

  use distance::{distance, distance_2d};
  use enums::Direction;
  use structs::{FloatPoint, Point};
  use traits::{HasValues, HasWalls};

  /// Return the floats one step along a line between two points
  ///
  /// The lerp is offset a small amount to prevent points from landing
  /// directly on the line between two hexes.
  pub fn step_size<T: HasValues>(a: &T, b: &T, step: f32) -> FloatPoint {

    let lerp = |x: i32, y: i32| 1e-6 + (y - x) as f32 * step;
    let (qa, ra, ta) = a.values();
    let (qb, rb, tb) = b.values();

    let result = FloatPoint::new(
      lerp(qa, qb),
      lerp(ra, rb),
      lerp(ta, tb),
    );

    result

  }

  /// Return the direction of one point which is one step after the other
  pub fn get_step_direction(point: &Point, other: &Point) -> Direction {

    let diff: Point = other - point;
    let (dq, dr, dt) = diff.values();

    match dt.signum() {
       1 => return Direction::Up,
      -1 => return Direction::Down,
       _ => (),
    }

    return match (dq.signum(), dr.signum()) {
      ( 1,  0) => Direction::East,
      ( 0,  1) => Direction::Southeast,
      (-1,  1) => Direction::Southwest,
      (-1,  0) => Direction::West,
      ( 0, -1) => Direction::Northwest,
      ( 1, -1) => Direction::Northeast,
      _ => panic!(),
    }

  }

  /// Find the points in a line between two points
  ///
  /// Optionally provide a range. The line will end at that range.
  ///
  /// Optionally provide a map with walls which are impassable.
  pub fn line<T: HasValues, U: HasWalls>(
    point: &T,
    other: &T,
    range: Option<i32>,
    map: Option<&HashMap<Point, U>>,
  ) -> HashSet<Point> {

    let mut set: HashSet<Point> = HashSet::new();

    set.insert(Point::from(point.values()));

    if point.values() == other.values() {
      return set;
    }

    let distance: i32 = if point.values_2d() == other.values_2d() {
      distance(point, other)
    } else {
      distance_2d(point, other)
    };

    let empty: HashMap<Point, U> = HashMap::new();
    let map: &HashMap<Point, U> = map.unwrap_or(&empty);

    let step: f32 = 1f32 / distance as f32;
    let size: FloatPoint = step_size(point, other, step);

    let mut found: FloatPoint = FloatPoint::from(point.values());
    let mut last: Point = Point::from(point.values());

    let has_wall = |point: &Point, dir: &Direction| match map.get(point) {
      Some(prism) => prism.has_wall(dir),
      None => false,
    };

    let has_wall = |point: &Point, other: &Point| {

      let dir: Direction = get_step_direction(point, other);
      let result = has_wall(point, &dir) || has_wall(other, &dir.opposite());

      result

    };

    let range: i32 = range.unwrap_or(distance);
    let mut steps: i32 = 0;

    // TODO This wip logic is broken. Tests fail. See github issue.
    'outer: for _ in 0 .. range {

      found = &found + &size;

      let round: Point = found.round();

      for t in last.t .. round.t {

        let vertical: Point = Point::new(round.q, round.r, t);

        if &vertical == &last {
          continue;
        }

        if has_wall(&last, &round) {
          break 'outer;
        }

        last = Point::from(vertical.values());
        set.insert(vertical);
        steps += 1;

        if steps == range {
          break 'outer;
        }

      }

      if has_wall(&last, &round) {
        break;
      }

      last = Point::from(round.values());
      set.insert(round);
      steps += 1;

      if steps == range {
        break;
      }

    }

    set

  }

}

#[cfg(test)]
mod tests {
  use std::collections::{HashSet, HashMap};

  use enums::Direction;
  use structs::{Point, Prism};
  use structs::FloatPoint;
  use traits::HasValues;

  use super::util;

  #[test]
  fn step_size() {
    let point: Point = Point::new(1, 2, 5);
    let other: Point = Point::new(1, 12, 5);
    let size: FloatPoint = util::step_size(&point, &other, 1f32);

    assert_eq!((1e-6, 10f32 + 1e-6, 1e-6), size.values());
  }

  #[test]
  fn line_vertical() {
    let point: Point = Point::new(1, 2, 5);
    let other: Point = Point::new(1, 2, 7);

    let line: HashSet<Point> = util::line(
      &point,
      &other,
      None,
      None::<&HashMap<Point, Prism>>
    );

    assert!(line.contains(&Point::new(1, 2, 5)));
    assert!(line.contains(&Point::new(1, 2, 6)));
    assert!(line.contains(&Point::new(1, 2, 7)));
    assert_eq!(line.len(), 3);
  }

  #[test]
  fn get_step_direction() {

    let point:     Point = Point::new(1, 2, 5);
    let east:      Point = Point::new(2, 2, 5);
    let southeast: Point = Point::new(1, 3, 5);
    let southwest: Point = Point::new(0, 3, 5);
    let west:      Point = Point::new(0, 2, 5);
    let northwest: Point = Point::new(1, 1, 5);
    let northeast: Point = Point::new(2, 1, 5);
    let up:        Point = Point::new(1, 2, 6);
    let down:      Point = Point::new(1, 2, 4);

    let get = util::get_step_direction;

    assert_eq!(Direction::East,      get(&point, &east));
    assert_eq!(Direction::Southeast, get(&point, &southeast));
    assert_eq!(Direction::Southwest, get(&point, &southwest));
    assert_eq!(Direction::West,      get(&point, &west));
    assert_eq!(Direction::Northwest, get(&point, &northwest));
    assert_eq!(Direction::Northeast, get(&point, &northeast));
    assert_eq!(Direction::Up,        get(&point, &up));
    assert_eq!(Direction::Down,      get(&point, &down));

  }

}

<|endoftext|>


<commit_before>extern crate chrono;

extern crate rustc_serialize;
use rustc_serialize::json;

extern crate rs_es;
use rs_es::Client;
use rs_es::operations::search::{Sort, SortField, Order};
use rs_es::query::{Filter, Query};

extern crate postgres;
extern crate postgres_array;
use postgres::{Connection, SslMode};

extern crate iron;
use iron::prelude::*;
use iron::status;
use iron::mime::Mime;

extern crate router;
use router::Router;

extern crate params;
use params::*;

mod user;
use user::User;

mod company;

mod filters;
use filters::{visibility_filters, VectorOfTerms};

use std::env;

#[derive(Debug, RustcDecodable)]
struct TalentsSearchResult {
  id: i32
}

const PG_URL:     &'static str            = "postgres://lando@localhost/lando_development";
const ES_INDEXES: &'static [&'static str] = &["honeypot_dev_talents"];
const VERSION:    &'static str            = env!("CARGO_PKG_VERSION");

fn main() {
  let port = env::args().nth(1).unwrap_or(String::from("3000"));
  let host = format!("127.0.0.1:{}", port);

  println!("Honeysearch v{}", VERSION);
  println!("Listening on http://{}...", host);

  let mut router = Router::new();
  router.get("/talents", talents);

  Iron::new(router).http(&*host).unwrap();
}

macro_rules! vec_from_params {
  ($params:expr, $param:expr) => {
    match $params.find(&[$param]) {
      Some(val) => Vec::from_value(val)
                       .unwrap_or(vec![]),
      None => vec![],
    }
  }
}

fn talents(req: &mut Request) -> IronResult<Response> {
  let mut es = Client::new("localhost", 9200);
  let     pg = Connection::connect(PG_URL, SslMode::None).unwrap();

  let params = req.get_ref::<Params>().ok().unwrap();

  let company_id = match params.find(&["company_id"]) {
    Some(company_id) => i32::from_value(company_id)
                            .map(|id| vec![id])
                            .unwrap_or(vec![]),
    None => vec![]
  };

  let query = Query::build_filtered(Filter::build_bool()
                                           .with_must(
                                             vec![
                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_roles", &vec_from_params!(params, "work_roles")),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_languages", &vec_from_params!(params, "work_languages")),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_experience", &vec_from_params!(params, "work_experience")),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_locations", &vec_from_params!(params, "work_locations")),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                "work_authorization", &vec_from_params!(params, "work_authorization")),

                                               visibility_filters(&pg, match company_id.is_empty() {
                                                 true  => None,
                                                 false => Some(company_id[0]),
                                               })
                                             ].into_iter()
                                              .flat_map(|x| x)
                                              .collect::<Vec<Filter>>())
                                           .with_must_not(
                                             vec![
                                               <Filter as VectorOfTerms<i32>>::build_terms(
                                                 "company_ids", &company_id),

                                               <Filter as VectorOfTerms<i32>>::build_terms(
                                                 "blocked_companies", &company_id)
                                             ].into_iter()
                                              .flat_map(|x| x)
                                              .collect::<Vec<Filter>>())
                                           .build())
                    .build();

  let result = es.search_query()
                 .with_indexes(ES_INDEXES)
                 .with_query(&query)
                 .with_sort(&Sort::new(
                   vec![
                     SortField::new("updated_at", Some(Order::Desc)).build()
                   ]))
                 .send()
                 .ok()
                 .unwrap();

  let user_ids = result.hits.hits.into_iter()
                                 .filter_map(|hit| {
                                   let talent: TalentsSearchResult = hit.source().unwrap();
                                   User::find(&pg, &talent.id)
                                 })
                                 .collect::<Vec<User>>();

  let content_type = "application/json".parse::<Mime>().unwrap();
  Ok(Response::with((content_type, status::Ok, json::encode(&user_ids).unwrap())))
}
<commit_msg>main: add tests<commit_after>extern crate chrono;

extern crate rustc_serialize;
use rustc_serialize::json;

extern crate rs_es;
use rs_es::Client;
use rs_es::operations::search::{Sort, SortField, Order};
use rs_es::query::{Filter, Query};

extern crate postgres;
extern crate postgres_array;
use postgres::{Connection, SslMode};

extern crate iron;
use iron::prelude::*;
use iron::status;
use iron::mime::Mime;

extern crate router;
use router::Router;

extern crate params;
use params::*;

mod user;
use user::User;

mod company;

mod filters;
use filters::{visibility_filters, VectorOfTerms};

use std::env;

#[derive(Debug, RustcDecodable)]
struct TalentsSearchResult {
  id: i32
}

const PG_URL:     &'static str            = "postgres://lando@localhost/lando_development";
const ES_INDEXES: &'static [&'static str] = &["honeypot_dev_talents"];
const VERSION:    &'static str            = env!("CARGO_PKG_VERSION");

fn main() {
  let port = env::args().nth(1).unwrap_or(String::from("3000"));
  let host = format!("127.0.0.1:{}", port);

  println!("Honeysearch v{}", VERSION);
  println!("Listening on http://{}...", host);

  let mut router = Router::new();
  router.get("/talents", talents);

  Iron::new(router).http(&*host).unwrap();
}

macro_rules! vec_from_params {
  ($params:expr, $param:expr) => {
    match $params.find(&[$param]) {
      Some(val) => Vec::from_value(val)
                       .unwrap_or(vec![]),
      None => vec![],
    }
  }
}

fn talents(req: &mut Request) -> IronResult<Response> {
  let mut es = Client::new("localhost", 9200);
  let     pg = Connection::connect(PG_URL, SslMode::None).unwrap();

  let params = req.get_ref::<Params>().ok().unwrap();

  let company_id = match params.find(&["company_id"]) {
    Some(company_id) => i32::from_value(company_id)
                            .map(|id| vec![id])
                            .unwrap_or(vec![]),
    None => vec![]
  };

  let query = Query::build_filtered(Filter::build_bool()
                                           .with_must(
                                             vec![
                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_roles", &vec_from_params!(params, "work_roles")),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_languages", &vec_from_params!(params, "work_languages")),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_experience", &vec_from_params!(params, "work_experience")),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_locations", &vec_from_params!(params, "work_locations")),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                "work_authorization", &vec_from_params!(params, "work_authorization")),

                                               visibility_filters(&pg, match company_id.is_empty() {
                                                 true  => None,
                                                 false => Some(company_id[0]),
                                               })
                                             ].into_iter()
                                              .flat_map(|x| x)
                                              .collect::<Vec<Filter>>())
                                           .with_must_not(
                                             vec![
                                               <Filter as VectorOfTerms<i32>>::build_terms(
                                                 "company_ids", &company_id),

                                               <Filter as VectorOfTerms<i32>>::build_terms(
                                                 "blocked_companies", &company_id)
                                             ].into_iter()
                                              .flat_map(|x| x)
                                              .collect::<Vec<Filter>>())
                                           .build())
                    .build();

  let result = es.search_query()
                 .with_indexes(ES_INDEXES)
                 .with_query(&query)
                 .with_sort(&Sort::new(
                   vec![
                     SortField::new("updated_at", Some(Order::Desc)).build()
                   ]))
                 .send()
                 .ok()
                 .unwrap();

  let user_ids = result.hits.hits.into_iter()
                                 .filter_map(|hit| {
                                   let talent: TalentsSearchResult = hit.source().unwrap();
                                   User::find(&pg, &talent.id)
                                 })
                                 .collect::<Vec<User>>();

  let content_type = "application/json".parse::<Mime>().unwrap();
  Ok(Response::with((content_type, status::Ok, json::encode(&user_ids).unwrap())))
}

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

  #[test]
  fn test_vec_from_params() {
    {
      let mut params = Map::new();
      params.assign("work_roles[]", Value::String("Fullstack".into())).unwrap();
      params.assign("work_roles[]", Value::String("DevOps".into())).unwrap();

      let work_roles: Vec<String> = vec_from_params!(params, "work_roles");
      assert_eq!(work_roles, vec!["Fullstack", "DevOps"]);
    }

    {
      let mut params = Map::new();
      params.assign("work_roles[]", Value::String("".into())).unwrap();

      let work_roles: Vec<String> = vec_from_params!(params, "work_roles");
      assert_eq!(work_roles, vec![""]); // vec![]?
    }

    {
      let work_roles: Vec<String> = vec_from_params!(Map::new(), "work_roles");
      assert_eq!(work_roles, Vec::<String>::new());
    }
  }

  macro_rules! i32_vec_from_params {
    ($params:expr, $param:expr) => {
      match $params.find(&[$param]) {
        Some(company_id) => i32::from_value(company_id)
                                .map(|id| vec![id])
                                .unwrap_or(vec![]),
        None => vec![]
      }
    }
  }

  #[test]
  fn test_company_id() {
    {
      let mut params = Map::new();
      params.assign("company_id", Value::String("4".into())).unwrap();

      let company_id: Vec<i32> = i32_vec_from_params!(params, "company_id");
      assert_eq!(company_id, vec![4]);
    }

    {
      let mut params = Map::new();
      params.assign("company_id", Value::String("".into())).unwrap();

      let company_id: Vec<i32> = i32_vec_from_params!(params, "company_id");
      assert_eq!(company_id, vec![]);
    }

    {
      let mut params = Map::new();
      params.assign("company_id", Value::String("madukapls".into())).unwrap();

      let company_id: Vec<i32> = i32_vec_from_params!(params, "company_id");
      assert_eq!(company_id, vec![]);
    }

    {
      let mut params = Map::new();
      params.assign("company_id[]", Value::String("madukapls".into())).unwrap();

      let company_id: Vec<i32> = i32_vec_from_params!(params, "company_id");
      assert_eq!(company_id, vec![]);
    }

    {
      let company_id: Vec<i32> = i32_vec_from_params!(Map::new(), "company_id");
      assert_eq!(company_id, vec![]);
    }
  }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Print help message with -h or --help flag<commit_after>use std::env;

const HELP_MESSAGE: &str = r#"
Usage:
  table -h | --help

Options:
  -h --help  Print help message
"#;

fn main() {
    for arg in env::args() {
        match &*arg {
            "-h" | "--help" => println!("{}", HELP_MESSAGE.trim()),
            _ => println!("TODO: implement other flags"),
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>make a shell that runs<commit_after>pub mod rsh;

use std::env;

fn main() {
    let mut argv = env::args();

    let path = argv.
        next().
        unwrap_or(".".to_string());

    let s = rsh::State::new(path);
    rsh::run(s)
}
<|endoftext|>


<commit_before>extern crate xml;

use std::os;

use std::io::{File, BufferedReader};
use std::fmt;

use xml::reader::EventReader;
use xml::reader::events::XmlEvent;
use xml::reader::events::XmlEvent::{StartElement, EndElement, Error};

fn indent(size: uint) -> String {
	let mut result = String::with_capacity(size*4);
	for _ in range(0, size) {
			result.push_str("    ");
	}
	result
}

fn main() {
	println!("XGConsole:");
	for arg in parse_command_line(os::args()).iter() {
		println!("  {}", arg);
	}
	sample();
}

fn parse_command_line(args: Vec<String>) -> Vec<String> {
	let mut result: Vec<String> = Vec::new();
	for arg in args.slice(1, args.len()).iter() {
			result.push(arg.clone());
	}
	result
}

struct IbTask {
name: String,
dependsOn: Vec<String>
}

impl fmt::Show for IbTask {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "name={}, dependsOn={}", self .name, self .dependsOn)
}
}

fn sample() {
	let file = File::open(&Path::new("tests/graph-parser.xml")).unwrap();
	let reader = BufferedReader::new(file);

	let mut parser = EventReader::new(reader);
	let mut depth = 0;
	for e in parser.events() {
		match e {
				StartElement { name, attributes, namespace} => {
				match name.local_name.as_slice() {
						"Task" =>
						{
							let mut task = IbTask {
							name: "".to_string(),
							dependsOn: vec![]
							};
							println!("{}/{} {}!", indent(depth), name, attributes);
							for attr in attributes.iter() {
								//let a : int = attr.value;
								match attr.name.local_name.as_slice()
									{
										"Name" =>
										{
												task.name = attr.value.to_string();
										}
										"DependsOn" =>
										{
											for item in attr.value.split_str(";").collect::<Vec<&str>>().iter() {
												println!(" deps: {}", item);
												task.dependsOn.push(item.to_string());
											}
										}
										_ =>
										{}
									}
								println!(" attr: {}", attr);
								println!(" task: {}", task);
							}
						}
						_ => {}
					}
				println!("{}/{}", indent(depth), name);
				depth += 1;
			}
				EndElement{name} => {
				depth -= 1;
				println!("{}/{}", indent(depth), name);
			}
				_ => {
			}
			}
	}
}
<commit_msg>Minimal tools and tasks parsing.<commit_after>extern crate xml;

use std::os;

use std::io::{File, BufferedReader};
use std::fmt;

use xml::reader::EventReader;
use xml::reader::events::XmlEvent;

fn main() {
	println!("XGConsole:");
	for arg in parse_command_line(os::args()).iter() {
		println!("  {}", arg);
	}
	sample();
}

fn parse_command_line(args: Vec<String>) -> Vec<String> {
	let mut result: Vec<String> = Vec::new();
	for arg in args.slice(1, args.len()).iter() {
			result.push(arg.clone());
	}
	result
}

enum OptionalString {
Value(String),
Missing,
}

impl fmt::Show for OptionalString {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	match self {
			&OptionalString::Value(ref v) => {
			write!(f, "{}", v)
		}
			&OptionalString::Missing => {
			write!(f, "missing")
		}
		}
}
}

struct XgTask {
id: OptionalString,
title: OptionalString,
tool: OptionalString,
working_dir: OptionalString,
depends_on: Vec<String>,
}

impl fmt::Show for XgTask {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "id={}, title={}, tool={}, working_dir={}, depends_on={}", self .id, self .title, self .tool, self .working_dir, self .depends_on)
}
}

struct XgTool {
id: OptionalString,
path: OptionalString,
params: OptionalString,
}

impl fmt::Show for XgTool {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "id={}, path={}", self .id, self .path)
}
}

fn sample() {
	let file = File::open(&Path::new("tests/graph-parser.xml")).unwrap();
	let reader = BufferedReader::new(file);

	let mut parser = EventReader::new(reader);
	let mut tasks:Vec<XgTask> = vec![];
	let mut tools:Vec<XgTool> = vec![];
	for e in parser.events() {
		match e {
				XmlEvent::StartElement {name, attributes, namespace} => {
				match name.local_name.as_slice() {
						"Task" =>
						{
								tasks.push(xg_parse_task(&attributes));
						}
						"Tool" =>
						{
								tools.push(xg_parse_tool(&attributes));
						}
						_ => {}
					}
			}
				XmlEvent::EndElement{name} => {
			}
				_ => {
			}
			}
	}
}

fn xg_parse_task (attributes: &Vec<xml::attribute::OwnedAttribute>)->XgTask {
	let mut task = XgTask {
	id: OptionalString::Missing,
	title: OptionalString::Missing,
	tool: OptionalString::Missing,
	working_dir: OptionalString::Missing,
	depends_on: vec![],
	};
	for attr in attributes.iter() {
		match attr.name.local_name.as_slice()
			{
				"Name" =>
				{
						task.id = OptionalString::Value(attr.value.to_string());
				}
				"Caption" =>
				{
						task.title = OptionalString::Value(attr.value.to_string());
				}
				"Tool" =>
				{
						task.tool = OptionalString::Value(attr.value.to_string());
				}
				"WorkingDir" =>
				{
						task.working_dir = OptionalString::Value(attr.value.to_string());
				}
				"DependsOn" =>
				{
					for item in attr.value.split_str(";").collect::<Vec<&str>>().iter() {
							task.depends_on.push(item.to_string());
					}
				}
				_ =>
				{
				}
			}
	}
	task
}
fn xg_parse_tool (attributes: &Vec<xml::attribute::OwnedAttribute>)->XgTool {
	let mut tool = XgTool {
	id: OptionalString::Missing,
	path: OptionalString::Missing,
	params: OptionalString::Missing,
	};
	for attr in attributes.iter() {
		match attr.name.local_name.as_slice()
			{
				"Name" =>
				{
						tool.id = OptionalString::Value(attr.value.to_string());
				}
				"Path" =>
				{
						tool.path = OptionalString::Value(attr.value.to_string());
				}
				"Params" =>
				{
						tool.params = OptionalString::Value(attr.value.to_string());
				}
				_ =>
				{
				}
			}
	}
	tool
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

mod logger;
mod toml_file;
mod git;
mod changelog;
mod commit_analyzer;
mod cargo;
mod error;
mod github;

extern crate rustc_serialize;
extern crate toml;
extern crate regex;
extern crate semver;
extern crate docopt;
extern crate git2;
extern crate clog;
extern crate hyper;
extern crate hubcaps;
extern crate url;

use docopt::Docopt;
use commit_analyzer::CommitType;
use std::process;
use semver::Version;
use std::{env,fs};
use std::path::Path;
use std::error::Error;
use url::Url;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USERAGENT: &'static str = concat!("semantic-rs/", env!("CARGO_PKG_VERSION"));
const USAGE: &'static str = "
semantic.rs 🚀

Usage:
  semantic-rs [options]
  semantic-rs --version

Options:
  -h --help              Show this screen.
  --version              Show version.
  -p PATH, --path=PATH   Specifies the repository path. [default: .]
  -w, --write            Run with writing the changes afterwards.
";

macro_rules! print_exit {
    ($fmt:expr) => {{
        logger::stderr(format!($fmt));
        process::exit(1);
    }};
    ($fmt:expr, $($arg:tt)*) => {{
        logger::stderr(format!($fmt, $($arg)*));
        process::exit(1);
    }};
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_path: String,
    flag_write: bool,
    flag_version: bool,
}

fn version_bump(version: &Version, bump: CommitType) -> Option<Version> {
    let mut version = version.clone();
    match bump {
        CommitType::Unknown => return None,
        CommitType::Patch => version.increment_patch(),
        CommitType::Minor => version.increment_minor(),
        CommitType::Major => version.increment_major(),
    }

    Some(version)
}

fn ci_env_set() -> bool {
    env::var("CI").is_ok()
}

fn user_repo_from_url(url: Url) -> Result<(String, String), String> {
    let path = match url.path() {
        Some(path) => path,
        None => return Err("URL should contain user and repository".into()),
    };

    let user = path[0].clone();
    let repo = match path[1].rfind(".git") {
        None => path[1].clone(),
        Some(suffix_pos) => {
            let valid_pos = path[1].len() - 4;
            if valid_pos == suffix_pos {
                let path = &path[1][0..suffix_pos];
                path.into()
            } else {
                return Err(".git suffix not at the end of URL".into())
            }
        }
    };

    Ok((user, repo))
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("semantic.rs 🚀 -- v{}", VERSION);
        process::exit(0);
    }

    let is_dry_run = if ci_env_set() {
        false
    }
    else {
        !args.flag_write
    };

    println!("semantic.rs 🚀");

    logger::stdout("Analyzing your repository");
    let path = Path::new(&args.flag_path);
    let path = fs::canonicalize(path)
        .unwrap_or_else(|_| print_exit!("Path does not exist or a component is not a directory"));
    let repository_path = path.to_str()
        .unwrap_or_else(|| print_exit!("Path is not valid unicode"));

    let repo = match git2::Repository::open(repository_path) {
        Ok(repo) => repo,
        Err(e) => {
            logger::stderr(format!("Could not open the git repository: {:?}", e));
            process::exit(1);
        }
    };

    let _signature = match git::get_signature(&repo) {
        Ok(sig) => sig,
        Err(e) => {
            logger::stderr(format!("Failed to get the committer's name and email address: {}", e.description()));
            logger::stderr(r"
A release commit needs a committer name and email address.
We tried fetching it from different locations, but couldn't find one.

Committer information is taken from the following environment variables, if set:

GIT_COMMITTER_NAME
GIT_COMMITTER_EMAIL

If none is set the normal git config is tried in the following order:

Local repository config
User config
Global config");
            process::exit(1);
        }
    };

    let remote_url = match repo.find_remote("origin") {
        Err(e) => {
            logger::stderr(format!("Could not determine the origin remote url: {:?}", e));
            process::exit(1);
        },
        Ok(remote) => {
            let url = remote.url().expect("Remote URL is not valid UTF-8");
            Url::parse(&url).expect("Remote URL can't be parsed")
        }
    };

    // TODO: Save those and re-use them later
    let (_user, _repo) = match user_repo_from_url(remote_url) {
        Ok(user_repo) => user_repo,
        Err(e) => {
            logger::stderr(format!("Could not extract user and repository name from URL: {:?}", e));
            process::exit(1);
        }
    };

    let version = toml_file::read_from_file(repository_path)
        .unwrap_or_else(|err| print_exit!("Reading `Cargo.toml` failed: {:?}", err));

    let version = Version::parse(&version).expect("Not a valid version");
    logger::stdout(format!("Current version: {}", version.to_string()));

    logger::stdout("Analyzing commits");

    let bump = git::version_bump_since_latest(repository_path);
    if is_dry_run {
        logger::stdout(format!("Commits analyzed. Bump would be {:?}", bump));
    }
    else {
        logger::stdout(format!("Commits analyzed. Bump will be {:?}", bump));
    }
    let new_version = match version_bump(&version, bump) {
        Some(new_version) => new_version.to_string(),
        None => {
            logger::stdout("No version bump. Nothing to do.");
            process::exit(0);
        }
    };

    if is_dry_run {
        logger::stdout(format!("New version would be: {}", new_version));
        logger::stdout("Would write the following Changelog:");
        let changelog = match changelog::generate(repository_path, &version.to_string(), &new_version) {
            Ok(log) => log,
            Err(err) => {
                logger::stderr(format!("Generating Changelog failed: {:?}", err));
                process::exit(1);
            }
        };
        logger::stdout("====================================");
        logger::stdout(changelog);
        logger::stdout("====================================");
        logger::stdout("Would create annotated git tag");
    }
    else {
        logger::stdout(format!("New version: {}", new_version));

        toml_file::write_new_version(repository_path, &new_version)
            .unwrap_or_else(|err| print_exit!("Writing `Cargo.toml` failed: {:?}", err));

        logger::stdout(format!("Writing Changelog"));
        changelog::write(repository_path, &version.to_string(), &new_version)
            .unwrap_or_else(|err| print_exit!("Writing Changelog failed: {:?}", err));

        logger::stdout("Updating lockfile");
        if !cargo::update_lockfile(repository_path) {
            print_exit!("`cargo fetch` failed. See above for the cargo error message.");
        }

        logger::stdout("Package crate");
        if !cargo::package(repository_path) {
            print_exit!("`cargo package` failed. See above for the cargo error message.");
        }

        git::commit_files(repository_path, &new_version)
            .unwrap_or_else(|err| print_exit!("Committing files failed: {:?}", err));

        logger::stdout("Creating annotated git tag");
        let tag_message = changelog::generate(repository_path, &version.to_string(), &new_version)
            .unwrap_or_else(|err| print_exit!("Can't generate changelog: {:?}", err));

        let tag_name = format!("v{}", new_version);
        git::tag(repository_path, &tag_name, &tag_message)
            .unwrap_or_else(|err| print_exit!("Failed to create git tag: {:?}", err));

        logger::stdout("Pushing new commit and tag");
        git::push(repository_path, &tag_name)
            .unwrap_or_else(|err| print_exit!("Failed to push git: {:?}", err));

        logger::stdout("Creating GitHub release");
        github::release(&tag_name, &tag_message)
            .unwrap_or_else(|err| print_exit!("Failed to create GitHub release: {:?}", err));
    }
}
<commit_msg>refactor: Use newer print_exit macro<commit_after>#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

mod logger;
mod toml_file;
mod git;
mod changelog;
mod commit_analyzer;
mod cargo;
mod error;
mod github;

extern crate rustc_serialize;
extern crate toml;
extern crate regex;
extern crate semver;
extern crate docopt;
extern crate git2;
extern crate clog;
extern crate hyper;
extern crate hubcaps;
extern crate url;

use docopt::Docopt;
use commit_analyzer::CommitType;
use std::process;
use semver::Version;
use std::{env,fs};
use std::path::Path;
use std::error::Error;
use url::Url;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USERAGENT: &'static str = concat!("semantic-rs/", env!("CARGO_PKG_VERSION"));
const USAGE: &'static str = "
semantic.rs 🚀

Usage:
  semantic-rs [options]
  semantic-rs --version

Options:
  -h --help              Show this screen.
  --version              Show version.
  -p PATH, --path=PATH   Specifies the repository path. [default: .]
  -w, --write            Run with writing the changes afterwards.
";

macro_rules! print_exit {
    ($fmt:expr) => {{
        logger::stderr(format!($fmt));
        process::exit(1);
    }};
    ($fmt:expr, $($arg:tt)*) => {{
        logger::stderr(format!($fmt, $($arg)*));
        process::exit(1);
    }};
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_path: String,
    flag_write: bool,
    flag_version: bool,
}

fn version_bump(version: &Version, bump: CommitType) -> Option<Version> {
    let mut version = version.clone();
    match bump {
        CommitType::Unknown => return None,
        CommitType::Patch => version.increment_patch(),
        CommitType::Minor => version.increment_minor(),
        CommitType::Major => version.increment_major(),
    }

    Some(version)
}

fn ci_env_set() -> bool {
    env::var("CI").is_ok()
}

fn user_repo_from_url(url: Url) -> Result<(String, String), String> {
    let path = match url.path() {
        Some(path) => path,
        None => return Err("URL should contain user and repository".into()),
    };

    let user = path[0].clone();
    let repo = match path[1].rfind(".git") {
        None => path[1].clone(),
        Some(suffix_pos) => {
            let valid_pos = path[1].len() - 4;
            if valid_pos == suffix_pos {
                let path = &path[1][0..suffix_pos];
                path.into()
            } else {
                return Err(".git suffix not at the end of URL".into())
            }
        }
    };

    Ok((user, repo))
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("semantic.rs 🚀 -- v{}", VERSION);
        process::exit(0);
    }

    let is_dry_run = if ci_env_set() {
        false
    }
    else {
        !args.flag_write
    };

    println!("semantic.rs 🚀");

    logger::stdout("Analyzing your repository");
    let path = Path::new(&args.flag_path);
    let path = fs::canonicalize(path)
        .unwrap_or_else(|_| print_exit!("Path does not exist or a component is not a directory"));
    let repository_path = path.to_str()
        .unwrap_or_else(|| print_exit!("Path is not valid unicode"));

    let repo = match git2::Repository::open(repository_path) {
        Ok(repo) => repo,
        Err(e) => {
            logger::stderr(format!("Could not open the git repository: {:?}", e));
            process::exit(1);
        }
    };

    let _signature = match git::get_signature(&repo) {
        Ok(sig) => sig,
        Err(e) => {
            logger::stderr(format!("Failed to get the committer's name and email address: {}", e.description()));
            logger::stderr(r"
A release commit needs a committer name and email address.
We tried fetching it from different locations, but couldn't find one.

Committer information is taken from the following environment variables, if set:

GIT_COMMITTER_NAME
GIT_COMMITTER_EMAIL

If none is set the normal git config is tried in the following order:

Local repository config
User config
Global config");
            process::exit(1);
        }
    };

    let remote_url = match repo.find_remote("origin") {
        Err(e) => print_exit!("Could not determine the origin remote url: {:?}", e),
        Ok(remote) => {
            let url = remote.url().expect("Remote URL is not valid UTF-8");
            Url::parse(&url).expect("Remote URL can't be parsed")
        }
    };

    // TODO: Save those and re-use them later
    let (_user, _repo) = user_repo_from_url(remote_url)
        .unwrap_or_else(|e| print_exit!("Could not extract user and repository name from URL: {:?}", e));

    let version = toml_file::read_from_file(repository_path)
        .unwrap_or_else(|err| print_exit!("Reading `Cargo.toml` failed: {:?}", err));

    let version = Version::parse(&version).expect("Not a valid version");
    logger::stdout(format!("Current version: {}", version.to_string()));

    logger::stdout("Analyzing commits");

    let bump = git::version_bump_since_latest(repository_path);
    if is_dry_run {
        logger::stdout(format!("Commits analyzed. Bump would be {:?}", bump));
    }
    else {
        logger::stdout(format!("Commits analyzed. Bump will be {:?}", bump));
    }
    let new_version = match version_bump(&version, bump) {
        Some(new_version) => new_version.to_string(),
        None => {
            logger::stdout("No version bump. Nothing to do.");
            process::exit(0);
        }
    };

    if is_dry_run {
        logger::stdout(format!("New version would be: {}", new_version));
        logger::stdout("Would write the following Changelog:");
        let changelog = match changelog::generate(repository_path, &version.to_string(), &new_version) {
            Ok(log) => log,
            Err(err) => {
                logger::stderr(format!("Generating Changelog failed: {:?}", err));
                process::exit(1);
            }
        };
        logger::stdout("====================================");
        logger::stdout(changelog);
        logger::stdout("====================================");
        logger::stdout("Would create annotated git tag");
    }
    else {
        logger::stdout(format!("New version: {}", new_version));

        toml_file::write_new_version(repository_path, &new_version)
            .unwrap_or_else(|err| print_exit!("Writing `Cargo.toml` failed: {:?}", err));

        logger::stdout(format!("Writing Changelog"));
        changelog::write(repository_path, &version.to_string(), &new_version)
            .unwrap_or_else(|err| print_exit!("Writing Changelog failed: {:?}", err));

        logger::stdout("Updating lockfile");
        if !cargo::update_lockfile(repository_path) {
            print_exit!("`cargo fetch` failed. See above for the cargo error message.");
        }

        logger::stdout("Package crate");
        if !cargo::package(repository_path) {
            print_exit!("`cargo package` failed. See above for the cargo error message.");
        }

        git::commit_files(repository_path, &new_version)
            .unwrap_or_else(|err| print_exit!("Committing files failed: {:?}", err));

        logger::stdout("Creating annotated git tag");
        let tag_message = changelog::generate(repository_path, &version.to_string(), &new_version)
            .unwrap_or_else(|err| print_exit!("Can't generate changelog: {:?}", err));

        let tag_name = format!("v{}", new_version);
        git::tag(repository_path, &tag_name, &tag_message)
            .unwrap_or_else(|err| print_exit!("Failed to create git tag: {:?}", err));

        logger::stdout("Pushing new commit and tag");
        git::push(repository_path, &tag_name)
            .unwrap_or_else(|err| print_exit!("Failed to push git: {:?}", err));

        logger::stdout("Creating GitHub release");
        github::release(&tag_name, &tag_message)
            .unwrap_or_else(|err| print_exit!("Failed to create GitHub release: {:?}", err));
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

use std::fmt;

use rocket::Outcome;
use rocket::request::{self, Request, FromRequest};

struct IndexData(String);

impl<'a, 'r> FromRequest<'a, 'r> for IndexData {
    type Error = ();
    fn from_request(request: &'a Request<'r>) -> request::Outcome<IndexData, ()> {
        Outcome::Success(IndexData(format!("{}", request)))
    }
}

impl fmt::Display for IndexData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[get("/")]
fn index() -> &'static str {
    "<!DOCTYPE html>

            <title>HTTPTIN</title>

    "
}

#[get("/test")]
fn test(data: IndexData) -> String {
    format!("<!DOCTYPE html><title>HTTPTIN></title>{}", data)
}

#[get("/ip")]
fn origin() -> String {
    String::from("Remote address decoding is not implemented yet")
}

#[get("/get")]
fn get() -> String {
    String::from("method")
}

#[get("/status/<status>")]
pub fn status(status: &str) -> String {
    format!("<!DOCTYPE html><title>HTTPTIN></title>Status: {} (FIX ME)", status)
}

fn main() {
    rocket::ignite().mount("/", routes![index, origin, get, status, test]).launch();
}
<commit_msg>Cleanup index.html<commit_after>#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

use std::fmt;

use rocket::Outcome;
use rocket::request::{self, Request, FromRequest};

struct IndexData(String);

impl<'a, 'r> FromRequest<'a, 'r> for IndexData {
    type Error = ();
    fn from_request(request: &'a Request<'r>) -> request::Outcome<IndexData, ()> {
        Outcome::Success(IndexData(format!("{}", request)))
    }
}

impl fmt::Display for IndexData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[get("/")]
fn index() -> content::HTML<&'static str> {
    content::HTML("<!DOCTYPE html>

            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ")
}

#[get("/test")]
fn test(data: IndexData) -> String {
    format!("<!DOCTYPE html><title>HTTPTIN></title>{}", data)
}

#[get("/ip")]
fn origin() -> String {
    String::from("Remote address decoding is not implemented yet")
}

#[get("/get")]
fn get() -> String {
    String::from("method")
}

#[get("/status/<status>")]
pub fn status(status: &str) -> String {
    format!("<!DOCTYPE html><title>HTTPTIN></title>Status: {} (FIX ME)", status)
}

fn main() {
    rocket::ignite().mount("/", routes![index, origin, get, status, test]).launch();
}
<|endoftext|>


<commit_before>// fs.rs
use std::env; // env::home_dir()
use std::fs; // fs::read_dir()
//use std::path::Path;
use std::path::PathBuf;

// allow ItemType to be cloned/copied
#[derive(Copy, Clone)]
enum ItemType {
   Dir,
   File,
   Other,
}

// allow FoundItem to be cloned/copied
#[derive(Copy, Clone)]
struct FoundItem {
   item_type: ItemType,
   item_path: PathBuf,
}

impl FoundItem {
   fn dump(self: FoundItem) {
      match self.item_type {
         // use .unwrap() to get the contents of the Option returned by
         // file_name()
         ItemType::Dir   => println!("d {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::File  => println!("f {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::Other => println!("o {:?}",
            self.item_path.file_name().unwrap()),
      }
   }
}

fn main() {
   //let mut idg_dir_path = PathBuf::from("~/Files/Doom/idgames");
   // create an empty PathBuf
   let mut idg_dir = PathBuf::new();
   // call `home_dir()` and act on what it returns
   match env::home_dir() {
      //Some(idg_dir) => println!("{}", idg_dir.display()),
      // home_dir() returned something
      Some(home_dir) => idg_dir = home_dir,
      // home_dir() returned nothing
      None => println!("Can't obtain home directory path!"),
   }

   // append more directories on to idg_dir
   idg_dir.push("Files");
   idg_dir.push("Doom");
   idg_dir.push("idgames");

   let mut items_v = Vec::new();
   let mut recurse_stack = Vec::new();
   // working example from:
   // https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_name
   // returns an array of DirEntry objects
   if let Ok(entries) = fs::read_dir(idg_dir) {
      // for each DirEntry object...
      for dir_entry in entries {

         // the item being tested/checked
         let item;

         if let Ok(dir_entry) = dir_entry {
            //let path = dir_entry.path();
            // get the metadata object for this DirEntry
            if let Ok(metadata) = dir_entry.metadata() {
               // below, `dir_entry` is a `DirEntry`.
               if metadata.is_file() {
                  item = FoundItem {
                     item_type: ItemType::File,
                     item_path: dir_entry.path()
                  };
               }
               else if metadata.is_dir() {
                  item = FoundItem {
                     item_type: ItemType::Dir,
                     item_path: dir_entry.path()
                  };
                  recurse_stack.push(item);
               }
               else {
                  item = FoundItem {
                     item_type: ItemType::Other,
                     item_path: dir_entry.path()
                  };

               }
               // push this items onto a Vec
               items_v.push(item);
            }
         }
      }
   }

   for item in items_v {
      // dump each item
      item.dump();
   }
/*
// doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
       let dir = try!(entry);
       println!("{:?}", dir.path());
   }
*/

/*
   // try and read the contents of idg_dir/
   // - doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
      let dir = try!(entry);
      // 'entry' is still a _Result_, so this is broken
      let metadata = try!(entry.metadata());
      // 'dir' is still a _DirEntry_
      if dir.is_dir() {
         println!("d {:?}", dir.path());
      } else {
         println!("! {:?}", dir.path());
      }
   }
*/

/*
   if let Ok(entries) = fs::read_dir(idg_dir) {
      for entry in entries {
         // 'item' is a Result, unwrap it to get access to Metadata
         if let Ok(entry) = entry {
               if let Ok(metadata) = entry.metadata() {};
               // entry.path() returns a _Result_
               if let Ok(path) = entry.path() {};
               // 'entry' is a _DirEntry_, and doesn't have an 'is_dir()'
               // method
               if entry.is_dir() {
                  println!("d {:?} {:?}",
                     // 'metadata' isn't available here
                     metadata.file_type(),
                     // the compiler doesn't know what 'path' is here
                     path);
            }
         }
      }
   }
*/

/*
   // working example
   println!("Updated іdgames/ path: {}", idg_dir.display());
   // read the contents of idg_dir/
   match fs::read_dir(idg_dir) {
      Err(why) => println!("! {:?}", why.kind()),
      Ok(paths) => for path in paths {
         println!("> {:?}", path.unwrap().path());
      }
   }
*/

}
<commit_msg>src/main.rs: PathBuf structs can't be Copy'ed<commit_after>// fs.rs
use std::env; // env::home_dir()
use std::fs; // fs::read_dir()
//use std::path::Path;
use std::path::PathBuf;

// allow ItemType to be cloned/copied
#[derive(Clone)]
enum ItemType {
   Dir,
   File,
   Other,
}

// allow FoundItem to be cloned/copied
#[derive(Clone)]
struct FoundItem {
   item_type: ItemType,
   item_path: PathBuf,
}

impl FoundItem {
   fn dump(self: FoundItem) {
      match self.item_type {
         // use .unwrap() to get the contents of the Option returned by
         // file_name()
         ItemType::Dir   => println!("d {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::File  => println!("f {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::Other => println!("o {:?}",
            self.item_path.file_name().unwrap()),
      }
   }
}

fn main() {
   //let mut idg_dir_path = PathBuf::from("~/Files/Doom/idgames");
   // create an empty PathBuf
   let mut idg_dir = PathBuf::new();
   // call `home_dir()` and act on what it returns
   match env::home_dir() {
      //Some(idg_dir) => println!("{}", idg_dir.display()),
      // home_dir() returned something
      Some(home_dir) => idg_dir = home_dir,
      // home_dir() returned nothing
      None => println!("Can't obtain home directory path!"),
   }

   // append more directories on to idg_dir
   idg_dir.push("Files");
   idg_dir.push("Doom");
   idg_dir.push("idgames");

   let mut items_v = Vec::new();
   let mut recurse_stack = Vec::new();
   // working example from:
   // https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_name
   // returns an array of DirEntry objects
   if let Ok(entries) = fs::read_dir(idg_dir) {
      // for each DirEntry object...
      for dir_entry in entries {

         // the item being tested/checked
         let item;

         if let Ok(dir_entry) = dir_entry {
            //let path = dir_entry.path();
            // get the metadata object for this DirEntry
            if let Ok(metadata) = dir_entry.metadata() {
               // below, `dir_entry` is a `DirEntry`.
               if metadata.is_file() {
                  item = FoundItem {
                     item_type: ItemType::File,
                     item_path: dir_entry.path()
                  };
               }
               else if metadata.is_dir() {
                  item = FoundItem {
                     item_type: ItemType::Dir,
                     item_path: dir_entry.path()
                  };
                  recurse_stack.push(item.clone());
               }
               else {
                  item = FoundItem {
                     item_type: ItemType::Other,
                     item_path: dir_entry.path()
                  };

               }
               // push this items onto a Vec
               items_v.push(item);
            }
         }
      }
   }

   for item in items_v {
      // dump each item
      item.dump();
   }
/*
// doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
       let dir = try!(entry);
       println!("{:?}", dir.path());
   }
*/

/*
   // try and read the contents of idg_dir/
   // - doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
      let dir = try!(entry);
      // 'entry' is still a _Result_, so this is broken
      let metadata = try!(entry.metadata());
      // 'dir' is still a _DirEntry_
      if dir.is_dir() {
         println!("d {:?}", dir.path());
      } else {
         println!("! {:?}", dir.path());
      }
   }
*/

/*
   if let Ok(entries) = fs::read_dir(idg_dir) {
      for entry in entries {
         // 'item' is a Result, unwrap it to get access to Metadata
         if let Ok(entry) = entry {
               if let Ok(metadata) = entry.metadata() {};
               // entry.path() returns a _Result_
               if let Ok(path) = entry.path() {};
               // 'entry' is a _DirEntry_, and doesn't have an 'is_dir()'
               // method
               if entry.is_dir() {
                  println!("d {:?} {:?}",
                     // 'metadata' isn't available here
                     metadata.file_type(),
                     // the compiler doesn't know what 'path' is here
                     path);
            }
         }
      }
   }
*/

/*
   // working example
   println!("Updated іdgames/ path: {}", idg_dir.display());
   // read the contents of idg_dir/
   match fs::read_dir(idg_dir) {
      Err(why) => println!("! {:?}", why.kind()),
      Ok(paths) => for path in paths {
         println!("> {:?}", path.unwrap().path());
      }
   }
*/

}
<|endoftext|>