<commit_before>/// Derives the next positional prefix array and divergence array
/// (Durbin's a_{k+1}[i] and d_{k+1}[i]) from the current ones
///
/// # Arguments
///
/// * `pos_prefix_array` - An array slice holding the positional prefix array (a_k[i])
/// * `div_array` - An array slice holding the divergence array (d_k[i])
/// * `haplotypes` - An array slice holding the haplotypes at the current (k-th) site
fn next_pp_and_div_arrays(pos_prefix_array: &[usize], div_array: &[usize], haplotypes: &[u8], k: usize) -> (Vec<usize>, Vec<usize>) {
    let mut allele_0_pos: Vec<usize> = vec![];
    let mut allele_0_div: Vec<usize> = vec![];
    let mut allele_1_pos: Vec<usize> = vec![];
    let mut allele_1_div: Vec<usize> = vec![];

    let mut match_0_start: usize = k + 1; // if this stays k+1, no match
    let mut match_1_start: usize = k + 1;

    for (&haplo_index, &start_of_match) in pos_prefix_array.iter().zip(div_array.iter()) {
        if start_of_match > div_0_index {
            match_0_start = start_of_match;
        }
        if start_of_match > div_1_index {
            match_1_start = start_of_match;
        }
        if haplotypes[haplo_index] == 0 {
            allele_0_pos.push(haplo_index);
            allele_0_div.push(match_0_start);
            match_0_start = 0;
        } else {
            allele_1_pos.push(haplo_index);
            allele_1_div.push(match_1_start);
            match_1_start = 0;
        }
    }
    let mut next_pp_array: Vec<usize> = vec![];
    next_pp_array.extend(allele_0_pos);
    next_pp_array.extend(allele_1_pos);
    let mut next_div_array: Vec<usize> = vec![];
    next_div_array.extend(allele_0_div);
    next_div_array.extend(allele_1_div);
    (next_pp_array, next_div_array)
}

/// Return the positional prefix and divergence arrays (Durbin's a_k[i] and d_k[i])
///
/// # Arguments
///
/// * `haplotypes` - An array slice in which each row (of length n_haplo)
///                  corresponds to a single site, and contains 0s and 1s
///                  indicating allele
/// * `n_haplo` - The number of haplotypes
/// * `k_site` - The numbered site to build the array for
fn build_pp_and_div_arrays(haplotypes: &[u8], n_haplo: usize, k_site: usize) -> (Vec<usize>, Vec<usize>) {
    let mut pos_prefix_array: Vec<usize> = vec![0; n_haplo];
    for i in 0..n_haplo {
        pos_prefix_array[i] = i;
    }
    let mut div_array: Vec<usize> = vec![0; n_haplo];

    for k in 0..(k_site-1) {
        let haplotypes_at_k = &haplotypes[k*n_haplo..(k+1)*n_haplo];
        let (pos_prefix_array_tmp, div_array_tmp) = next_pp_and_div_arrays(&pos_prefix_array, &div_array, &haplotypes_at_k, k);
        pos_prefix_array = pos_prefix_array_tmp;
        div_array = div_array_tmp;
    }
    (pos_prefix_array, div_array)
}

fn main() {
}

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

    #[test]
    fn test_pp_and_div_arrays() {
        let n_haplo: usize = 8;
        let n_sites: usize = 6;
        let haplotypes: Vec<u8> = vec![0, 1, 1, 0, 0, 1, 1, 0,
                                       1, 1, 1, 1, 0, 0, 1, 1,
                                       0, 0, 1, 1, 0, 0, 0, 0,
                                       1, 0, 1, 1, 0, 0, 0, 1,
                                       0, 0, 1, 1, 0, 1, 0, 1,
                                       1, 1, 1, 0, 0, 0, 1, 0];
        let expected_pp_1: Vec<usize> = (0..8).collect();
        let expected_div_1: Vec<usize> = vec![0; 8];
        let (pp_1, div_1) = build_pp_and_div_arrays(&haplotypes, n_haplo, 1);
        assert_eq!(&expected_pp_1, &pp_1);
        assert_eq!(&expected_div_1, &div_1);
        let expected_pp_6: Vec<usize> = vec![4, 1, 6, 0, 5, 7, 3, 2];
        let expected_div_6: Vec<usize> = vec![5, 2, 0, 4, 5, 4, 3, 1];
        let (pp_6, div_6) = build_pp_and_div_arrays(&haplotypes, n_haplo, n_sites);
        assert_eq!(&expected_pp_6, &pp_6);
        assert_eq!(&expected_div_6, &div_6);
    }
}
<commit_msg>Progress at algorithm 3: reporting long matches, but need to test and refactor<commit_after>#[derive(Debug)]
struct Match {
    haplo_a: Vec<usize>,
    haplo_b: Vec<usize>,
    end: usize,
}

/// Find long matches and compute the next positional prefix
/// array and divergence array (Durbin's a_{k+1}[i] and d_{k+1}[i])
/// from the current ones
///
/// # Arguments
///
/// * `pos_prefix_array` - An array slice holding the positional prefix array (a_k[i])
/// * `div_array` - An array slice holding the divergence array (d_k[i])
/// * `haplotypes` - An array slice holding the haplotypes at the current (k-th) site
/// * `min_size` - The minimun length match to return
fn find_long_matches(pos_prefix_array: &[usize], div_array: &[usize], haplotypes: &[u8], k: usize, min_size: usize) -> (Vec<Match>, Vec<usize>, Vec<usize>) {
    let mut allele_0_pos: Vec<usize> = vec![];
    let mut allele_0_div: Vec<usize> = vec![];
    let mut allele_0_match: Vec<usize> = vec![];
    let mut allele_1_pos: Vec<usize> = vec![];
    let mut allele_1_div: Vec<usize> = vec![];
    let mut allele_1_match: Vec<usize> = vec![];

    let mut match_0_start: usize = k + 1; // if this stays k+1, no match
    let mut match_1_start: usize = k + 1;

    let mut matches: Vec<Match> = vec![];

    for (&haplo_index, &start_of_match) in pos_prefix_array.iter().zip(div_array.iter()) {
        if start_of_match + min_size > k {
            if !allele_0_match.is_empty() || !allele_1_match.is_empty() {
                matches.push(Match{haplo_a: allele_0_match.clone(), haplo_b: allele_1_match.clone(), end: k});
            }
            allele_0_match = vec![];
            allele_1_match = vec![];
        }

        if start_of_match > match_0_start {
            match_0_start = start_of_match;
        }
        if start_of_match > match_1_start {
            match_1_start = start_of_match;
        }
        if haplotypes[haplo_index] == 0 {
            allele_0_pos.push(haplo_index);
            allele_0_div.push(match_0_start);
            allele_0_match.push(haplo_index);
            match_0_start = 0;
        } else {
            allele_1_pos.push(haplo_index);
            allele_1_div.push(match_1_start);
            allele_1_match.push(haplo_index);
            match_1_start = 0;
        }
    }

    if !allele_0_match.is_empty() || !allele_1_match.is_empty() {
        matches.push(Match{haplo_a: allele_0_match.clone(), haplo_b: allele_1_match.clone(), end: k});
    }

    let mut next_pp_array: Vec<usize> = vec![];
    next_pp_array.extend(allele_0_pos);
    next_pp_array.extend(allele_1_pos);
    let mut next_div_array: Vec<usize> = vec![];
    next_div_array.extend(allele_0_div);
    next_div_array.extend(allele_1_div);
    (matches, next_pp_array, next_div_array)
}

/// Find all long matches and return the positional prefix and divergence arrays (Durbin's a_k[i] and d_k[i])
///
/// # Arguments
///
/// * `haplotypes` - An array slice in which each row (of length n_haplo)
///                  corresponds to a single site, and contains 0s and 1s
///                  indicating allele
/// * `n_haplo` - The number of haplotypes
/// * `k_site` - The numbered site to build the array for
/// * `min_size` - The minimun length match to return
fn find_all_long_matches(haplotypes: &[u8], n_haplo: usize, k_site: usize, min_size: usize) -> (Vec<Match>, Vec<usize>, Vec<usize>) {
    let mut pos_prefix_array: Vec<usize> = vec![0; n_haplo];
    for i in 0..n_haplo {
        pos_prefix_array[i] = i;
    }
    let mut div_array: Vec<usize> = vec![0; n_haplo];
    let mut all_matches: Vec<Match> = vec![];

    for k in 0..(k_site-1) {
        let haplotypes_at_k = &haplotypes[k*n_haplo..(k+1)*n_haplo];
        let (matches, pos_prefix_array_tmp, div_array_tmp) = find_long_matches(&pos_prefix_array, &div_array, &haplotypes_at_k, k, min_size);
        pos_prefix_array = pos_prefix_array_tmp;
        div_array = div_array_tmp;
        all_matches.extend(matches);
    }
    (all_matches, pos_prefix_array, div_array)
}

fn main() {
    let n_haplo: usize = 4;
    let n_sites: usize = 7;
    let haplotypes: Vec<u8> = vec![1, 1, 0, 1,
                                   0, 1, 1, 1,
                                   1, 1, 1, 1,
                                   0, 1, 1, 0,
                                   1, 1, 0, 0,
                                   1, 0, 1, 0,
                                   0, 1, 1, 1];
    let (matches, pp_1, div_1) = find_all_long_matches(&haplotypes, n_haplo, 7, 2);
    println!("{:?}", matches);
    println!("{:?}", pp_1);
    println!("{:?}", div_1);
}

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

    #[test]
    fn test_pp_and_div_arrays() {
        let n_haplo: usize = 8;
        let n_sites: usize = 6;
        let haplotypes: Vec<u8> = vec![0, 1, 1, 0, 0, 1, 1, 0,
                                       1, 1, 1, 1, 0, 0, 1, 1,
                                       0, 0, 1, 1, 0, 0, 0, 0,
                                       1, 0, 1, 1, 0, 0, 0, 1,
                                       0, 0, 1, 1, 0, 1, 0, 1,
                                       1, 1, 1, 0, 0, 0, 1, 0];
        let expected_pp_1: Vec<usize> = (0..8).collect();
        let expected_div_1: Vec<usize> = vec![0; 8];
        let (matches_1, pp_1, div_1) = find_all_long_matches(&haplotypes, n_haplo, 1, 3);
        assert_eq!(&expected_pp_1, &pp_1);
        assert_eq!(&expected_div_1, &div_1);
        let expected_pp_6: Vec<usize> = vec![4, 1, 6, 0, 5, 7, 3, 2];
        let expected_div_6: Vec<usize> = vec![5, 2, 0, 4, 5, 4, 3, 1];
        let (matches_6, pp_6, div_6) = find_all_long_matches(&haplotypes, n_haplo, n_sites, 3);
        assert_eq!(&expected_pp_6, &pp_6);
        assert_eq!(&expected_div_6, &div_6);
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016 Cormac O'Brien
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std;

pub use std::f32::consts::PI as PI;

pub struct Mat4(pub [[f32; 4]; 4]);

impl std::ops::Deref for Mat4 {
    type Target = [[f32; 4]; 4];

    fn deref(&self) -> &[[f32; 4]; 4] {
        &self.0
    }
}

impl std::ops::Mul for Mat4 {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self {
        let mut result = [[0.0; 4]; 4];
        for i in 0..4 {
            for j in 0..4 {
                for k in 0..4 {
                    result[i][j] += self[k][j] * rhs[i][k];
                }
            }
        }
        Mat4(result)
    }
}

impl Mat4 {
    pub fn identity() -> Self {
        Mat4([[1.0, 0.0, 0.0, 0.0],
              [0.0, 1.0, 0.0, 0.0],
              [0.0, 0.0, 1.0, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    pub fn rotation_x(theta: f32) -> Self {
        let s = theta.sin();
        let c = theta.cos();
        Mat4([[1.0, 0.0, 0.0, 0.0],
              [0.0,   c,   s, 0.0],
              [0.0,  -s,   c, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    pub fn rotation_y(theta: f32) -> Self {
        let s = theta.sin();
        let c = theta.cos();
        Mat4([[  c, 0.0,   s, 0.0],
              [0.0, 1.0, 0.0, 0.0],
              [ -s, 0.0,   c, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    pub fn rotation_z(theta: f32) -> Self {
        let s = theta.sin();
        let c = theta.cos();
        Mat4([[  c,   s, 0.0, 0.0],
              [ -s,   c, 0.0, 0.0],
              [0.0, 0.0, 1.0, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    pub fn translation(x: f32, y: f32, z: f32) -> Self {
        Mat4([[1.0, 0.0, 0.0, 0.0],
              [0.0, 1.0, 0.0, 0.0],
              [0.0, 0.0, 1.0, 0.0],
              [  x,   y,   z, 1.0]])
    }
}
<commit_msg>Add Vec3 type to math module<commit_after>// Copyright © 2016 Cormac O'Brien
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std;

pub use std::f32::consts::PI as PI;

pub struct Mat4(pub [[f32; 4]; 4]);

impl std::ops::Deref for Mat4 {
    type Target = [[f32; 4]; 4];

    fn deref(&self) -> &[[f32; 4]; 4] {
        &self.0
    }
}

impl std::ops::Mul for Mat4 {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self {
        let mut result = [[0.0; 4]; 4];
        for i in 0..4 {
            for j in 0..4 {
                for k in 0..4 {
                    result[i][j] += self[k][j] * rhs[i][k];
                }
            }
        }
        Mat4(result)
    }
}

impl Mat4 {
    pub fn identity() -> Self {
        Mat4([[1.0, 0.0, 0.0, 0.0],
              [0.0, 1.0, 0.0, 0.0],
              [0.0, 0.0, 1.0, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    pub fn rotation_x(theta: f32) -> Self {
        let s = theta.sin();
        let c = theta.cos();
        Mat4([[1.0, 0.0, 0.0, 0.0],
              [0.0,   c,   s, 0.0],
              [0.0,  -s,   c, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    pub fn rotation_y(theta: f32) -> Self {
        let s = theta.sin();
        let c = theta.cos();
        Mat4([[  c, 0.0,   s, 0.0],
              [0.0, 1.0, 0.0, 0.0],
              [ -s, 0.0,   c, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    pub fn rotation_z(theta: f32) -> Self {
        let s = theta.sin();
        let c = theta.cos();
        Mat4([[  c,   s, 0.0, 0.0],
              [ -s,   c, 0.0, 0.0],
              [0.0, 0.0, 1.0, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    pub fn translation(x: f32, y: f32, z: f32) -> Self {
        Mat4([[1.0, 0.0, 0.0, 0.0],
              [0.0, 1.0, 0.0, 0.0],
              [0.0, 0.0, 1.0, 0.0],
              [  x,   y,   z, 1.0]])
    }
}

pub struct Vec3([f32; 3]);

impl std::ops::Index<usize> for Vec3 {
    type Output = f32;

    fn index(&self, i: usize) -> &f32 {
        &self.0[i]
    }
}

impl Vec3 {
    pub fn dot<V>(&self, other: V) -> Vec3 where V: AsRef<Vec3> {
        let o = other.as_ref();
        Vec3 ([self[0] * o[0], self[1] * o[1], self[2] * o[2]])
    }
}
<|endoftext|>


<commit_before>extern mod extra;

pub struct Pipe<T,U>{
  priv chan: Chan<T>,
  priv port: Port<U>
}
pub struct SingleWire;

enum Message<T> {
    Exit,
    Value(T)
}
trait Wire<T: Send,U: Send> {
  fn connect(&self, f: ~fn(T)->U,port: Port<Message<T>>) -> Port<Message<U>>;
}
trait Sender<T: Send, U: Send>{
  fn send(&self, t: T);
  fn shutdown(&self);

}
trait Receiver<T: Send, U: Send> {
  fn recv(&self) -> Option<U>;
  fn recv_wait(&self) -> U;
}
impl <T: Send,U: Send> Pipe<Message<T>,Message<U>>{
    fn drop(&self) {
        self.shutdown(); // doesn't work
    }
}
impl <T: Send,U: Send> Pipe<Message<T>,Message<U>>{
  pub fn new(f: ~fn(Port<T>) -> Port<U>)-> Pipe<T,U> {
    let (in_port, chan): (Port<T>, Chan<T>) = stream();
    let out_port = f(in_port);
    Pipe { chan: chan,
           port: out_port}
  }
}
impl <T: Send,U: Send> Sender<T,U> for Pipe<Message<T>,Message<U>>{

  fn send(&self, t: T) {
      self.chan.send(Value(t));
  }

  fn shutdown(&self) {
     self.chan.send(Exit);
     loop {
       match self.port.recv() {
         Exit => return,
         _    => ()
       }
     }
  }
}
impl <T: Send,U: Send> Receiver<T,U> for Pipe<Message<T>,Message<U>> {
  fn recv(&self) -> Option<U>{
    match self.port.peek() {
      true  => Some(self.recv_wait()),
      false => None
    }
  }

  fn recv_wait(&self) -> U {
    match self.port.recv(){
      Exit => fail!(~"Tried to receive on 'Exit'"),
      Value(x) => x
    }
  }
}

impl<T: Send,U: Send> Wire<T,U> for SingleWire  {
      fn connect(&self, f: ~fn(T)->U,port: Port<Message<T>>) -> Port<Message<U>> {
        let (out_port, out_chan): (Port<Message<U>>, Chan<Message<U>>) = stream();
        do ::std::task::spawn_unlinked {
          loop {
            let msg = port.recv();
            match msg {
              Exit => {
                out_chan.send(Exit);
                fail!(~"Exit");
              }
              Value(x) => out_chan.send(Value(f(x)))
            }
          }
        }
        out_port
    }
}

<commit_msg>remove type<commit_after>extern mod extra;

pub struct Pipe<T,U>{
  priv chan: Chan<T>,
  priv port: Port<U>
}
pub struct SingleWire;

enum Message<T> {
    Exit,
    Value(T)
}
trait Wire<T: Send,U: Send> {
  fn connect(&self, f: ~fn(T)->U,port: Port<Message<T>>) -> Port<Message<U>>;
}
trait Sender<T: Send>{
  fn send(&self, t: T);
  fn shutdown(&self);

}
trait Receiver<U: Send> {
  fn recv(&self) -> Option<U>;
  fn recv_wait(&self) -> U;
}
impl <T: Send,U: Send> Pipe<Message<T>,Message<U>>{
    fn drop(&self) {
        self.shutdown(); // doesn't work
    }
}
impl <T: Send,U: Send> Pipe<Message<T>,Message<U>>{
  pub fn new(f: ~fn(Port<T>) -> Port<U>)-> Pipe<T,U> {
    let (in_port, chan): (Port<T>, Chan<T>) = stream();
    let out_port = f(in_port);
    Pipe { chan: chan,
           port: out_port}
  }
}
impl <T: Send,U: Send> Sender<T> for Pipe<Message<T>,Message<U>>{
  fn send(&self, t: T) {
      self.chan.send(Value(t));
  }

  fn shutdown(&self) {
     self.chan.send(Exit);
     loop {
       match self.port.recv() {
         Exit => return,
         _    => ()
       }
     }
  }
}
impl <T: Send,U: Send> Receiver<U> for Pipe<Message<T>,Message<U>> {
  fn recv(&self) -> Option<U>{
    match self.port.peek() {
      true  => Some(self.recv_wait()),
      false => None
    }
  }

  fn recv_wait(&self) -> U {
    match self.port.recv(){
      Exit => fail!(~"Tried to receive on 'Exit'"),
      Value(x) => x
    }
  }
}

impl<T: Send,U: Send> Wire<T,U> for SingleWire  {
      fn connect(&self, f: ~fn(T)->U,port: Port<Message<T>>) -> Port<Message<U>> {
        let (out_port, out_chan): (Port<Message<U>>, Chan<Message<U>>) = stream();
        do ::std::task::spawn_unlinked {
          loop {
            let msg = port.recv();
            match msg {
              Exit => {
                out_chan.send(Exit);
                fail!(~"Exit");
              }
              Value(x) => out_chan.send(Value(f(x)))
            }
          }
        }
        out_port
    }
}

<|endoftext|>


<commit_before>use std::ops::Add;
use std::num::{Float, FromPrimitive, ToPrimitive, FromStrRadix};
use std::cmp::min;
use std::fmt;
use std::fmt::Writer;
use std::f64;

use num::bigint::{BigInt, ToBigInt};
use num::rational::{Ratio, BigRational};
use num::{Signed, Zero, Integer, CheckedAdd};

#[derive(PartialEq, Debug)]
pub enum Real {
    Fixnum(isize),
    Integer(BigInt),
    Rational(BigRational),
    Flonum(f64)
}

impl fmt::Display for Real {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Real::Fixnum(n) => write!(f, "{}", n),
            &Real::Integer(ref n) => write!(f, "{}", n),
            &Real::Rational(ref n) => write!(f, "{}", n),
            &Real::Flonum(n) => write!(f, "{}", n)
        }
    }
}

#[inline]
pub fn fix2int(n: isize) -> BigInt {
    n.to_bigint().unwrap()
}

#[inline]
pub fn int2rat(n: BigInt) -> BigRational {
    Ratio::from_integer(n)
}

#[inline]
pub fn fix2rat(n: isize) -> BigRational {
    int2rat(fix2int(n))
}

#[inline]
pub fn fix2flo(n: isize) -> f64 {
    FromPrimitive::from_int(n).unwrap()
}

pub fn int2flo(n: &BigInt) -> f64 {
    if n.is_zero() {
        return 0f64;
    }

    let neg = *n < Zero::zero();
    let repr = {
        let mut digits = Vec::new();
        let mut m = n.abs();
        let base: BigInt = FromPrimitive::from_u64(1 << 32).unwrap();
        while m >= base {
            let (q, r) = m.div_mod_floor(&base);
            digits.push(r.to_uint().unwrap());
            m = q;
        }
        if !m.is_zero() {
            digits.push(m.to_uint().unwrap());
        }
        let mut s = String::new();
        for &d in digits.iter().rev() {
            write!(&mut s, "{}", fmt::radix(d, 2)).unwrap();
        }
        s
    };
    let mantissa_repr = &repr[0 .. min(f64::MANTISSA_DIGITS, repr.len())];
    let u_mantissa:i64 = FromStrRadix::from_str_radix(mantissa_repr,
                                                        2).unwrap();
    let i_mantissa = if neg {
        -u_mantissa
    } else {
        u_mantissa
    };
    let exp = (repr.len() - mantissa_repr.len()) as isize;
    let m:f64 = i_mantissa.to_f64().unwrap();
    return Float::ldexp(m, exp);
}

pub fn rat2flo(r: &BigRational) -> f64 {
    int2flo(r.numer()) / int2flo(r.denom())
}

fn coerce<Fix, Big, Rat, Flo>(lhs: Real, rhs: Real,
                              fix_op: Fix, big_op: Big,
                              rat_op: Rat, flo_op: Flo)
        -> Real
    where Fix: Fn(isize, isize) -> Option<isize>,
          Big: Fn(BigInt, BigInt) -> BigInt,
          Rat: Fn(BigRational, BigRational) -> BigRational,
          Flo: Fn(f64, f64) -> f64
{
    match (lhs, rhs) {
        (Real::Fixnum(l), Real::Fixnum(r)) =>
            match fix_op(l, r) {
                Some(n) => Real::Fixnum(n),
                None => Real::Integer(big_op(fix2int(l), fix2int(r)))
            },
        (Real::Fixnum(l), Real::Integer(r)) =>
            Real::Integer(big_op(fix2int(l), r)),
        (Real::Fixnum(l), Real::Rational(r)) =>
            Real::Rational(rat_op(fix2rat(l), r)),
        (Real::Fixnum(l), Real::Flonum(r)) =>
            Real::Flonum(flo_op(fix2flo(l), r)),
        (Real::Integer(l), Real::Fixnum(r)) =>
            Real::Integer(big_op(l, fix2int(r))),
        (Real::Integer(l), Real::Integer(r)) =>
            Real::Integer(big_op(l, r)),
        (Real::Integer(l), Real::Rational(r)) =>
            Real::Rational(rat_op(int2rat(l), r)),
        (Real::Integer(ref l), Real::Flonum(r)) =>
            Real::Flonum(flo_op(int2flo(l), r)),
        (Real::Rational(l), Real::Fixnum(r)) =>
            Real::Rational(rat_op(l, fix2rat(r))),
        (Real::Rational(l), Real::Integer(r)) =>
            Real::Rational(rat_op(l, int2rat(r))),
        (Real::Rational(l), Real::Rational(r)) =>
            Real::Rational(rat_op(l, r)),
        (Real::Rational(ref l), Real::Flonum(r)) =>
            Real::Flonum(flo_op(rat2flo(l), r)),
        (Real::Flonum(l), Real::Fixnum(r)) =>
            Real::Flonum(flo_op(l, fix2flo(r))),
        (Real::Flonum(l), Real::Integer(ref r)) =>
            Real::Flonum(flo_op(l, int2flo(r))),
        (Real::Flonum(l), Real::Rational(ref r)) =>
            Real::Flonum(flo_op(l, rat2flo(r))),
        (Real::Flonum(l), Real::Flonum(r)) =>
            Real::Flonum(flo_op(l, r))
    }
}

impl Add<Real> for Real {
    type Output = Real;

    fn add(self, other: Real) -> <Real as Add<Real>>::Output {
        coerce(self, other,
               |x, y| x.checked_add(&y),
               |x, y| x + y,
               |x, y| x + y,
               |x, y| x + y)
    }
}

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

    #[test]
    fn test_add() {
        assert_eq!(Real::Fixnum(3), Real::Fixnum(1) + Real::Fixnum(2));
    }
}
<commit_msg>impl PartialEq and PartialOrd for Real<commit_after>use std::ops::Add;
use std::num::{Float, FromPrimitive, ToPrimitive, FromStrRadix};
use std::cmp::min;
use std::fmt;
use std::fmt::Writer;
use std::f64;
use std::cmp::Ordering;

use num::bigint::{BigInt, ToBigInt};
use num::rational::{Ratio, BigRational};
use num::{Signed, Zero, Integer, CheckedAdd};

#[derive(Debug)]
pub enum Real {
    Fixnum(isize),
    Integer(BigInt),
    Rational(BigRational),
    Flonum(f64)
}

impl fmt::Display for Real {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Real::Fixnum(n) => write!(f, "{}", n),
            &Real::Integer(ref n) => write!(f, "{}", n),
            &Real::Rational(ref n) => write!(f, "{}", n),
            &Real::Flonum(n) => write!(f, "{}", n)
        }
    }
}

#[inline]
pub fn fix2int(n: isize) -> BigInt {
    n.to_bigint().unwrap()
}

#[inline]
pub fn int2rat(n: &BigInt) -> BigRational {
    Ratio::from_integer(n.clone())
}

#[inline]
pub fn fix2rat(n: isize) -> BigRational {
    int2rat(&fix2int(n))
}

#[inline]
pub fn fix2flo(n: isize) -> f64 {
    FromPrimitive::from_int(n).unwrap()
}

pub fn int2flo(n: &BigInt) -> f64 {
    if n.is_zero() {
        return 0f64;
    }

    let neg = *n < Zero::zero();
    let repr = {
        let mut digits = Vec::new();
        let mut m = n.abs();
        let base: BigInt = FromPrimitive::from_u64(1 << 32).unwrap();
        while m >= base {
            let (q, r) = m.div_mod_floor(&base);
            digits.push(r.to_uint().unwrap());
            m = q;
        }
        if !m.is_zero() {
            digits.push(m.to_uint().unwrap());
        }
        let mut s = String::new();
        for &d in digits.iter().rev() {
            write!(&mut s, "{}", fmt::radix(d, 2)).unwrap();
        }
        s
    };
    let mantissa_repr = &repr[0 .. min(f64::MANTISSA_DIGITS, repr.len())];
    let u_mantissa:i64 = FromStrRadix::from_str_radix(mantissa_repr,
                                                        2).unwrap();
    let i_mantissa = if neg {
        -u_mantissa
    } else {
        u_mantissa
    };
    let exp = (repr.len() - mantissa_repr.len()) as isize;
    let m:f64 = i_mantissa.to_f64().unwrap();
    return Float::ldexp(m, exp);
}

pub fn rat2flo(r: &BigRational) -> f64 {
    int2flo(r.numer()) / int2flo(r.denom())
}

fn coerce_arith<Fix, Big, Rat, Flo>(lhs: &Real, rhs: &Real,
                                    fix_op: Fix, big_op: Big,
                                    rat_op: Rat, flo_op: Flo)
        -> Real
    where Fix: Fn(isize, isize) -> Option<isize>,
          Big: Fn(&BigInt, &BigInt) -> BigInt,
          Rat: Fn(&BigRational, &BigRational) -> BigRational,
          Flo: Fn(f64, f64) -> f64
{
    coerce(lhs, rhs,
           |x, y| match fix_op(x, y) {
               Some(n) => Real::Fixnum(n),
               None => Real::Integer(big_op(&fix2int(x), &fix2int(y)))
           },
           |x, y| Real::Integer(big_op(x, y)),
           |x, y| Real::Rational(rat_op(x, y)),
           |x, y| Real::Flonum(flo_op(x, y))
    )
}

fn coerce<Fix, Big, Rat, Flo, T>(lhs: &Real, rhs: &Real,
                                 fix_op: Fix, big_op: Big,
                                 rat_op: Rat, flo_op: Flo)
        -> T
    where Fix: Fn(isize, isize) -> T,
          Big: Fn(&BigInt, &BigInt) -> T,
          Rat: Fn(&BigRational, &BigRational) -> T,
          Flo: Fn(f64, f64) -> T
{
    match (lhs, rhs) {
        (&Real::Fixnum(l), &Real::Fixnum(r)) =>
            fix_op(l, r),
        (&Real::Fixnum(l), &Real::Integer(ref r)) =>
            big_op(&fix2int(l), r),
        (&Real::Fixnum(l), &Real::Rational(ref r)) =>
            rat_op(&fix2rat(l), r),
        (&Real::Fixnum(l), &Real::Flonum(r)) =>
            flo_op(fix2flo(l), r),
        (&Real::Integer(ref l), &Real::Fixnum(r)) =>
            big_op(l, &fix2int(r)),
        (&Real::Integer(ref l), &Real::Integer(ref r)) =>
            big_op(l, r),
        (&Real::Integer(ref l), &Real::Rational(ref r)) =>
            rat_op(&int2rat(l), r),
        (&Real::Integer(ref l), &Real::Flonum(r)) =>
            flo_op(int2flo(l), r),
        (&Real::Rational(ref l), &Real::Fixnum(r)) =>
            rat_op(l, &fix2rat(r)),
        (&Real::Rational(ref l), &Real::Integer(ref r)) =>
            rat_op(l, &int2rat(r)),
        (&Real::Rational(ref l), &Real::Rational(ref r)) =>
            rat_op(l, r),
        (&Real::Rational(ref l), &Real::Flonum(r)) =>
            flo_op(rat2flo(l), r),
        (&Real::Flonum(l), &Real::Fixnum(r)) =>
            flo_op(l, fix2flo(r)),
        (&Real::Flonum(l), &Real::Integer(ref r)) =>
            flo_op(l, int2flo(r)),
        (&Real::Flonum(l), &Real::Rational(ref r)) =>
            flo_op(l, rat2flo(r)),
        (&Real::Flonum(l), &Real::Flonum(r)) =>
            flo_op(l, r)
    }
}

impl Add<Real> for Real {
    type Output = Real;

    fn add(self, other: Real) -> Real {
        coerce_arith(&self, &other,
                     |x, y| x.checked_add(&y),
                     |x, y| x + y,
                     |x, y| x + y,
                     |x, y| x + y)
    }
}

impl<'a, 'b> Add<&'a Real> for &'b Real {
    type Output = Real;

    fn add(self, other: &Real) -> Real {
        coerce_arith(self, other,
                     |x, y| x.checked_add(&y),
                     |x, y| x + y,
                     |x, y| x + y,
                     |x, y| x + y)
    }
}

impl PartialEq for Real {
    fn eq(&self, other: &Real) -> bool {
        coerce(self, other,
               |x, y| x == y,
               |x, y| x == y,
               |x, y| x == y,
               |x, y| x == y
        )
    }
}

impl PartialOrd for Real {
    fn partial_cmp(&self, other: &Real) -> Option<Ordering> {
        coerce(self, other,
                    |x, y| x.partial_cmp(&y),
                    |x, y| x.partial_cmp(y),
                    |x, y| x.partial_cmp(y),
                    |x, y| x.partial_cmp(&y)
        )
    }
}

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

    #[test]
    fn test_add() {
        assert_eq!(Real::Fixnum(3), Real::Fixnum(1) + Real::Fixnum(2));
    }
}
<|endoftext|>


<commit_before>// (c) 2016-2017 Productize SPRL <joost@productize.be>

use std::fmt;
use std::result;
use std::str::FromStr;
use std::mem;

use Result;

/// like Into trait but works from a ref avoiding consumption or expensive clone
pub trait IntoSexp {
    /// convert self into a Sexp
    fn into_sexp(&self) -> Sexp;
}

impl Into<Sexp> for Vec<Sexp> {
    fn into(self: Vec<Sexp>) -> Sexp {
        Sexp::List(self)
    }
}

impl Into<Sexp> for String {
    fn into(self: String) -> Sexp {
        Sexp::String(self)
    }
}

impl<'a> From<&'a str> for Sexp {
    fn from(t: &str) -> Sexp {
        Sexp::String(t.into())
    }
}

impl<'a> From<&'a String> for Sexp {
    fn from(t: &String) -> Sexp {
        Sexp::String(t.clone())
    }
}

impl Into<Sexp> for i64 {
    fn into(self: i64) -> Sexp {
        Sexp::String(format!("{}", self))
    }
}

impl Into<Sexp> for f64 {
    fn into(self: f64) -> Sexp {
        Sexp::String(format!("{}", self))
    }
}

impl<'a> From<(&'a str, Sexp)> for Sexp {
    fn from(kv: (&str, Sexp)) -> Sexp {
        let (name, value) = kv;
        let mut v = vec![];
        v.push(name.into());
        v.push(value);
        v.into()
    }
}

impl<'a, T: fmt::Display> From<(&'a str, &'a T)> for Sexp {
    fn from(kv: (&str, &T)) -> Sexp {
        let (name, value) = kv;
        let mut v = vec![];
        v.push(name.into());
        v.push(format!("{}", value).into());
        v.into()
    }
}

impl<'a> From<&'a Sexp> for Result<f64> {
    fn from(s:&Sexp) -> Result<f64> {
        s.f()
    }
}

/// a symbolic-expression
/// Can be a string or a list or nothing
#[derive(Debug, Clone, PartialEq)]
pub enum Sexp {
    /// plain String symbolic-expression
    String(String),
    /// list symbolic-expression
    List(Vec<Sexp>),
    /// empty, trivial symbolic-expression
    Empty,
}

// Following the KiCad file formats specification chapter 4.4 - Identifiers and Strings:
// A string may not contain an actual newline or carriage return,
// but it may use an escape sequence to encode a // newline, such as \n.
// If a string has any of the following conditions, then it must be quoted
// with a leading and trailing double quote
// character, otherwise it is acceptable to not quote the string:
// 1. has one or more of the following 4 separator bytes: ASCII space,
// tab, '(', or ')'.
// 2. has one or more of the following bytes: '%', '{', or '}'.
// 3. has a length of zero bytes, and you need a place holder for the field,
//  then use "".
// 4. includes a byte of '-', and this byte is not in the first position of
// the string.
//

// Joost remark: kicad no longer seems to follow Rule 4.
// so we don't either

/// encode a string according to the guidelines given by Kicad
pub fn encode_string(s: &str) -> String {
    // fn rule_4(s:&str) -> bool {
    // s.contains('-') && s.len() > 1 && s.as_bytes()[0] != 45
    // }
    if s.contains('(') || s.contains(' ') || s.contains(')') || s.contains('\t') ||
       s.contains('{') || s.contains('}') || s.contains('}') || s.contains('%') ||
       s.is_empty()
    // || rule_4(s)
    {
        format!("\"{}\"", s)
    } else {
        String::from(s)
    }
}

impl Sexp {
    /// create an empty symbolic-expression
    #[deprecated(since="4.0.0", note="please use `Sexp::default()` instead")]
    pub fn new_empty() -> Sexp {
        Sexp::Empty
    }

    /// create a String type symbolic-expression
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_string<T>(s: T) -> Sexp
        where T: fmt::Display
    {
        format!("{}", s).into()
    }

    /// create a list type symbolic-expression
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_list(v: Vec<Sexp>) -> Sexp {
        Sexp::List(v)
    }

    /// create an empty list type symbolic-expression
    pub fn start(name: &str) -> Sexp {
        let mut v = vec![];
        v.push(Sexp::String(name.into()));
        Sexp::List(v)
    }

    /// push an element in a list
    pub fn push<T: Into<Sexp>>(&mut self, element: T) {
        match *self {
            Sexp::List(ref mut v) => v.push(element.into()),
            _ => panic!("Only use push on lists!"),
        }
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name, the remainder is filled in via the provided
    /// fill function
    pub fn new_named_list<F>(name: &str, fill: F) -> Sexp
        where F: Fn(&mut Vec<Sexp>)
    {
        let mut v = vec![];
        v.push(name.into());
        fill(&mut v);
        Sexp::List(v)
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_named<T>(name: &str, value: T) -> Sexp
        where T: fmt::Display
    {
        let mut v = vec![];
        v.push(name.into());
        v.push(format!("{}", value).into());
        v.into()
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name, and the second is another symbolic-expression
    /// created via the IntoSexp trait
    #[deprecated(since="4.0.5", note="please use `.into()` on a tuple instead")]
    pub fn new_named_sexp<T>(name: &str, value: &T) -> Sexp
        where T: IntoSexp
    {
        let mut v = vec![];
        v.push(name.into());
        v.push(value.into_sexp());
        Sexp::List(v)
    }

    /// if the expression is a list, take out the list and swap it with Empty
    pub fn take_list(&mut self) -> Result<Vec<Sexp>> {
        let mut e = Sexp::Empty;
        mem::swap(&mut e, self);
        match e {
            Sexp::List(v) => Ok(v),
            _ => Err(format!("Not a list: {}", e).into()),
        }
    }

    /// if the expression is a string, take it out and swap it with Empty
    pub fn take_string(&mut self) -> Result<String> {
        let mut e = Sexp::Empty;
        mem::swap(&mut e, self);
        match e {
            Sexp::String(s) => Ok(s),
            _ => Err(format!("Not a string: {}", e).into()),
        }
    }

    /// create a symbolic-expression via the IntoSexp trait
    pub fn from<T: IntoSexp>(t: &T) -> Sexp {
        t.into_sexp()
    }

    /// access the symbolic-expression as if it is a List
    pub fn list(&self) -> Result<&Vec<Sexp>> {
        match *self {
            Sexp::List(ref v) => Ok(v),
            _ => Err(format!("not a list: {}", self).into()),
        }
    }

    /// access the symbolic-expression as if it is a String
    pub fn string(&self) -> Result<&String> {
        match *self {
            Sexp::String(ref s) => Ok(s),
            _ => Err(format!("not a string: {}", self).into()),
        }
    }

    /// is this expression a string
    pub fn is_string(&self) -> bool {
        match *self {
            Sexp::String(_) => true,
            _ => false,
        }
    }

    /// is this expression a list
    pub fn is_list(&self) -> bool {
        match *self {
            Sexp::List(_) => true,
            _ => false,
        }
    }

    /// access the symbolic-expression as if it is a String
    /// that is a f64
    pub fn f(&self) -> Result<f64> {
        let s = self.string()?;
        let f = f64::from_str(s)?;
        Ok(f)
    }

    /// access the symbolic-expression as if it is a String
    /// that is an i64
    pub fn i(&self) -> Result<i64> {
        let s = self.string()?;
        let i = i64::from_str(s)?;
        Ok(i)
    }

    /// access the symbolic-expression as if it is a List
    /// assuming the first element is a String and return that
    pub fn list_name(&self) -> Result<&String> {
        let l = self.list()?;
        let l = &l[..];
        let a = l[0].string()?;
        Ok(a)
    }

    /// access the symbolic-expression as if it is a named List
    /// where the name is provided and returns the remaining elements
    /// after the name as a slice
    pub fn slice_atom(&self, s: &str) -> Result<&[Sexp]> {
        let v = self.list()?;
        let v2 = &v[..];
        let st = v2[0].string()?;
        if st != s {
            return Err(format!("list {} doesn't start with {}, but with {}", self, s, st).into());
        };
        Ok(&v[1..])
    }

    /// access the symbolic-expression as if it is a named List
    /// with two elements where the name is provided and returns
    /// the next element in the list
    pub fn named_value(&self, s: &str) -> Result<&Sexp> {
        let v = self.list()?;
        if v.len() != 2 {
            return Err(format!("list {} is not a named_value", s).into());
        }
        let l = self.slice_atom(s)?;
        Ok(&l[0])
    }

    /// as named_value but converted to i64
    pub fn named_value_i(&self, s: &str) -> Result<i64> {
        self.named_value(s)?.i()
    }

    /// as named_value but converted to f64
    pub fn named_value_f(&self, s: &str) -> Result<f64> {
        self.named_value(s)?.f()
    }

    /// as named_value but converted to String
    pub fn named_value_string(&self, s: &str) -> Result<&String> {
        self.named_value(s)?.string()
    }

    /// get the symbolic-expression as a list which starts
    /// with a string that indicates the name and has num more
    /// elements, returns those elements
    pub fn slice_atom_num(&self, s: &str, num: usize) -> Result<&[Sexp]> {
        let v = self.list()?;
        let v2 = &v[..];
        let st = v2[0].string()?;
        if st != s {
            return Err(format!("list doesn't start with {}, but with {}", s, st).into());
        };
        if v.len() != (num + 1) {
            return Err(format!("list ({}) doesn't have {} elements but {}",
                               s,
                               num,
                               v.len() - 1)
                .into());
        }
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        match *self {
            Sexp::String(ref s) => write!(f, "{}", encode_string(s)),
            Sexp::List(ref v) => {
                write!(f, "(")?;
                let l = v.len();
                for (i, x) in v.iter().enumerate() {
                    if i < l - 1 {
                        write!(f, "{} ", x)?;
                    } else {
                        write!(f, "{}", x)?;
                    }
                }
                write!(f, ")")
            }
            Sexp::Empty => Ok(()),
        }
    }
}

impl Default for Sexp {
    fn default() -> Sexp {
        Sexp::Empty
    }
}
<commit_msg>"get a field" test<commit_after>// (c) 2016-2017 Productize SPRL <joost@productize.be>

use std::fmt;
use std::result;
use std::str::FromStr;
use std::mem;

use Result;
/// like Into trait but works from a ref avoiding consumption or expensive clone
pub trait IntoSexp {
    /// convert self into a Sexp
    fn into_sexp(&self) -> Sexp;
}

impl Into<Sexp> for Vec<Sexp> {
    fn into(self: Vec<Sexp>) -> Sexp {
        Sexp::List(self)
    }
}

impl Into<Sexp> for String {
    fn into(self: String) -> Sexp {
        Sexp::String(self)
    }
}

impl<'a> From<&'a str> for Sexp {
    fn from(t: &str) -> Sexp {
        Sexp::String(t.into())
    }
}

impl<'a> From<&'a String> for Sexp {
    fn from(t: &String) -> Sexp {
        Sexp::String(t.clone())
    }
}

impl Into<Sexp> for i64 {
    fn into(self: i64) -> Sexp {
        Sexp::String(format!("{}", self))
    }
}

impl Into<Sexp> for f64 {
    fn into(self: f64) -> Sexp {
        Sexp::String(format!("{}", self))
    }
}

impl<'a> From<(&'a str, Sexp)> for Sexp {
    fn from(kv: (&str, Sexp)) -> Sexp {
        let (name, value) = kv;
        let mut v = vec![];
        v.push(name.into());
        v.push(value);
        v.into()
    }
}

impl<'a, T: fmt::Display> From<(&'a str, &'a T)> for Sexp {
    fn from(kv: (&str, &T)) -> Sexp {
        let (name, value) = kv;
        let mut v = vec![];
        v.push(name.into());
        v.push(format!("{}", value).into());
        v.into()
    }
}

/// a symbolic-expression
/// Can be a string or a list or nothing
#[derive(Debug, Clone, PartialEq)]
pub enum Sexp {
    /// plain String symbolic-expression
    String(String),
    /// list symbolic-expression
    List(Vec<Sexp>),
    /// empty, trivial symbolic-expression
    Empty,
}

// Following the KiCad file formats specification chapter 4.4 - Identifiers and Strings:
// A string may not contain an actual newline or carriage return,
// but it may use an escape sequence to encode a // newline, such as \n.
// If a string has any of the following conditions, then it must be quoted
// with a leading and trailing double quote
// character, otherwise it is acceptable to not quote the string:
// 1. has one or more of the following 4 separator bytes: ASCII space,
// tab, '(', or ')'.
// 2. has one or more of the following bytes: '%', '{', or '}'.
// 3. has a length of zero bytes, and you need a place holder for the field,
//  then use "".
// 4. includes a byte of '-', and this byte is not in the first position of
// the string.
//

// Joost remark: kicad no longer seems to follow Rule 4.
// so we don't either

/// encode a string according to the guidelines given by Kicad
pub fn encode_string(s: &str) -> String {
    // fn rule_4(s:&str) -> bool {
    // s.contains('-') && s.len() > 1 && s.as_bytes()[0] != 45
    // }
    if s.contains('(') || s.contains(' ') || s.contains(')') || s.contains('\t') ||
       s.contains('{') || s.contains('}') || s.contains('}') || s.contains('%') ||
       s.is_empty()
    // || rule_4(s)
    {
        format!("\"{}\"", s)
    } else {
        String::from(s)
    }
}

impl Sexp {
    /// create an empty symbolic-expression
    #[deprecated(since="4.0.0", note="please use `Sexp::default()` instead")]
    pub fn new_empty() -> Sexp {
        Sexp::Empty
    }

    /// create a String type symbolic-expression
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_string<T>(s: T) -> Sexp
        where T: fmt::Display
    {
        format!("{}", s).into()
    }

    /// create a list type symbolic-expression
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_list(v: Vec<Sexp>) -> Sexp {
        Sexp::List(v)
    }

    /// create an empty list type symbolic-expression
    pub fn start(name: &str) -> Sexp {
        let mut v = vec![];
        v.push(Sexp::String(name.into()));
        Sexp::List(v)
    }

    /// push an element in a list
    pub fn push<T: Into<Sexp>>(&mut self, element: T) {
        match *self {
            Sexp::List(ref mut v) => v.push(element.into()),
            _ => panic!("Only use push on lists!"),
        }
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name, the remainder is filled in via the provided
    /// fill function
    pub fn new_named_list<F>(name: &str, fill: F) -> Sexp
        where F: Fn(&mut Vec<Sexp>)
    {
        let mut v = vec![];
        v.push(name.into());
        fill(&mut v);
        Sexp::List(v)
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_named<T>(name: &str, value: T) -> Sexp
        where T: fmt::Display
    {
        let mut v = vec![];
        v.push(name.into());
        v.push(format!("{}", value).into());
        v.into()
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name, and the second is another symbolic-expression
    /// created via the IntoSexp trait
    #[deprecated(since="4.0.5", note="please use `.into()` on a tuple instead")]
    pub fn new_named_sexp<T>(name: &str, value: &T) -> Sexp
        where T: IntoSexp
    {
        let mut v = vec![];
        v.push(name.into());
        v.push(value.into_sexp());
        Sexp::List(v)
    }

    /// if the expression is a list, take out the list and swap it with Empty
    pub fn take_list(&mut self) -> Result<Vec<Sexp>> {
        let mut e = Sexp::Empty;
        mem::swap(&mut e, self);
        match e {
            Sexp::List(v) => Ok(v),
            _ => Err(format!("Not a list: {}", e).into()),
        }
    }

    /// if the expression is a string, take it out and swap it with Empty
    pub fn take_string(&mut self) -> Result<String> {
        let mut e = Sexp::Empty;
        mem::swap(&mut e, self);
        match e {
            Sexp::String(s) => Ok(s),
            _ => Err(format!("Not a string: {}", e).into()),
        }
    }

    /// create a symbolic-expression via the IntoSexp trait
    pub fn from<T: IntoSexp>(t: &T) -> Sexp {
        t.into_sexp()
    }

    /// access the symbolic-expression as if it is a List
    pub fn list(&self) -> Result<&Vec<Sexp>> {
        match *self {
            Sexp::List(ref v) => Ok(v),
            _ => Err(format!("not a list: {}", self).into()),
        }
    }

    /// access the symbolic-expression as if it is a String
    pub fn string(&self) -> Result<&String> {
        match *self {
            Sexp::String(ref s) => Ok(s),
            _ => Err(format!("not a string: {}", self).into()),
        }
    }

    /// is this expression a string
    pub fn is_string(&self) -> bool {
        match *self {
            Sexp::String(_) => true,
            _ => false,
        }
    }

    /// is this expression a list
    pub fn is_list(&self) -> bool {
        match *self {
            Sexp::List(_) => true,
            _ => false,
        }
    }

    /// access the symbolic-expression as if it is a String
    /// that is a f64
    pub fn f(&self) -> Result<f64> {
        let s = self.string()?;
        let f = f64::from_str(s)?;
        Ok(f)
    }

    /// access the symbolic-expression as if it is a String
    /// that is an i64
    pub fn i(&self) -> Result<i64> {
        let s = self.string()?;
        let i = i64::from_str(s)?;
        Ok(i)
    }

    /// get a field
    pub fn get<T, E>(&self) -> result::Result<T, E>
        where T: FromStr,
              E: From<::Error> + From<<T as FromStr>::Err>
    {
        let s = self.string()?;
        let x: T = s.parse()?;
        Ok(x)
    }

    /// access the symbolic-expression as if it is a List
    /// assuming the first element is a String and return that
    pub fn list_name(&self) -> Result<&String> {
        let l = self.list()?;
        let l = &l[..];
        let a = l[0].string()?;
        Ok(a)
    }

    /// access the symbolic-expression as if it is a named List
    /// where the name is provided and returns the remaining elements
    /// after the name as a slice
    pub fn slice_atom(&self, s: &str) -> Result<&[Sexp]> {
        let v = self.list()?;
        let v2 = &v[..];
        let st = v2[0].string()?;
        if st != s {
            return Err(format!("list {} doesn't start with {}, but with {}", self, s, st).into());
        };
        Ok(&v[1..])
    }

    /// access the symbolic-expression as if it is a named List
    /// with two elements where the name is provided and returns
    /// the next element in the list
    pub fn named_value(&self, s: &str) -> Result<&Sexp> {
        let v = self.list()?;
        if v.len() != 2 {
            return Err(format!("list {} is not a named_value", s).into());
        }
        let l = self.slice_atom(s)?;
        Ok(&l[0])
    }

    /// as named_value but converted to i64
    pub fn named_value_i(&self, s: &str) -> Result<i64> {
        self.named_value(s)?.i()
    }

    /// as named_value but converted to f64
    pub fn named_value_f(&self, s: &str) -> Result<f64> {
        self.named_value(s)?.f()
    }

    /// as named_value but converted to String
    pub fn named_value_string(&self, s: &str) -> Result<&String> {
        self.named_value(s)?.string()
    }

    /// get the symbolic-expression as a list which starts
    /// with a string that indicates the name and has num more
    /// elements, returns those elements
    pub fn slice_atom_num(&self, s: &str, num: usize) -> Result<&[Sexp]> {
        let v = self.list()?;
        let v2 = &v[..];
        let st = v2[0].string()?;
        if st != s {
            return Err(format!("list doesn't start with {}, but with {}", s, st).into());
        };
        if v.len() != (num + 1) {
            return Err(format!("list ({}) doesn't have {} elements but {}",
                               s,
                               num,
                               v.len() - 1)
                .into());
        }
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        match *self {
            Sexp::String(ref s) => write!(f, "{}", encode_string(s)),
            Sexp::List(ref v) => {
                write!(f, "(")?;
                let l = v.len();
                for (i, x) in v.iter().enumerate() {
                    if i < l - 1 {
                        write!(f, "{} ", x)?;
                    } else {
                        write!(f, "{}", x)?;
                    }
                }
                write!(f, ")")
            }
            Sexp::Empty => Ok(()),
        }
    }
}

impl Default for Sexp {
    fn default() -> Sexp {
        Sexp::Empty
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use std::thread;
use std::time as stdtime;

use time;

use scheduler::Scheduler;
use cron::CronEntry;
use error::Error;

use job::Job;
use output_keeper::OutputKeeper;

pub struct Task<'a, 'b: 'a> {
    scheduler: Scheduler<'a>,
    cron: CronEntry,
    keeper: &'a OutputKeeper<'b>,
    job: Option<Job<'a, 'b>>,
}

impl<'a, 'b: 'a> Task<'a, 'b> {
    pub fn new(sch: Scheduler<'a>, cron: CronEntry, keeper: &'b OutputKeeper) -> Task<'a, 'b> {
        Task {
            scheduler: sch,
            cron: cron,
            job: None,
            keeper: keeper,
        }
    }

    // start() periodically make a new job and then execute it in background.
    pub fn start(&mut self) {
        loop {
            let tm = time::now();

            if self.scheduler.isTimeUp(&tm) {
                let mut job = Job::new(100, self.cron.to_command(), self.keeper);
                job.start();
            }

            // sleep
            thread::sleep(stdtime::Duration::from_millis(1000 * (60-tm.tm_sec)));
        }
    }

    // fn is_running(&self) -> bool {
    //     //TODO: fix it, and make it public
    //     false
    // }
}
<commit_msg>fix(task): fix time unit<commit_after>use std::str::FromStr;
use std::thread;
use std::time as stdtime;

use time;

use scheduler::Scheduler;
use cron::CronEntry;
use error::Error;

use job::Job;
use output_keeper::OutputKeeper;

pub struct Task<'a, 'b: 'a> {
    scheduler: Scheduler<'a>,
    cron: CronEntry,
    keeper: &'a OutputKeeper<'b>,
    job: Option<Job<'a, 'b>>,
}

impl<'a, 'b: 'a> Task<'a, 'b> {
    pub fn new(sch: Scheduler<'a>, cron: CronEntry, keeper: &'b OutputKeeper) -> Task<'a, 'b> {
        Task {
            scheduler: sch,
            cron: cron,
            job: None,
            keeper: keeper,
        }
    }

    // start() periodically make a new job and then execute it in background.
    pub fn start(&mut self) {
        loop {
            let tm = time::now();

            if self.scheduler.isTimeUp(&tm) {
                let mut job = Job::new(100, self.cron.to_command(), self.keeper);
                job.start();
            }

            // sleep
            thread::sleep(stdtime::Duration::from_millis(1000u64 * (60u64-tm.tm_sec)));
        }
    }

    // fn is_running(&self) -> bool {
    //     //TODO: fix it, and make it public
    //     false
    // }
}
<|endoftext|>


<commit_before>use std::io::{Read, Write};
use std::net::TcpStream;
use winapi;

use schannel_cred::{Direction, Protocol, Algorithm, SchannelCred};
use tls_stream;

#[test]
fn basic() {
    let creds = SchannelCred::builder().acquire(Direction::Outbound).unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut out = vec![];
    stream.read_to_end(&mut out).unwrap();
    assert!(out.starts_with(b"HTTP/1.0 200 OK"));
    assert!(out.ends_with(b""));
}

#[test]
fn invalid_algorithms() {
    let creds = SchannelCred::builder()
        .supported_algorithms(&[Algorithm::Rc2, Algorithm::Ecdsa])
        .acquire(Direction::Outbound);
    assert_eq!(creds.err().unwrap().raw_os_error().unwrap(),
               winapi::SEC_E_ALGORITHM_MISMATCH as i32);
}

#[test]
fn valid_algorithms() {
    let creds = SchannelCred::builder()
        .supported_algorithms(&[Algorithm::Aes128, Algorithm::Ecdsa])
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut out = vec![];
    stream.read_to_end(&mut out).unwrap();
    assert!(out.starts_with(b"HTTP/1.0 200 OK"));
    assert!(out.ends_with(b""));
}

#[test]
#[ignore] // google's inconsistent about disallowing sslv3
fn invalid_protocol() {
    let creds = SchannelCred::builder()
        .enabled_protocols(&[Protocol::Ssl3])
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::SEC_E_UNSUPPORTED_FUNCTION as i32);
}

#[test]
fn valid_protocol() {
    let creds = SchannelCred::builder()
        .enabled_protocols(&[Protocol::Tls12])
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut out = vec![];
    stream.read_to_end(&mut out).unwrap();
    assert!(out.starts_with(b"HTTP/1.0 200 OK"));
    assert!(out.ends_with(b""));
}

#[test]
fn expired_cert() {
    let creds = SchannelCred::builder()
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("expired.badssl.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("expired.badssl.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::CERT_E_EXPIRED as i32);
}

#[test]
fn self_signed_cert() {
    let creds = SchannelCred::builder()
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("self-signed.badssl.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("self-signed.badssl.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::CERT_E_UNTRUSTEDROOT as i32);
}

#[test]
fn wrong_host_cert() {
    let creds = SchannelCred::builder()
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("wrong.host.badssl.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("wrong.host.badssl.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::CERT_E_CN_NO_MATCH as i32);
}

#[test]
fn shutdown() {
    let creds = SchannelCred::builder().acquire(Direction::Outbound).unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.shutdown().unwrap();
}

#[test]
fn validation_failure_is_permanent() {
    let creds = SchannelCred::builder().acquire(Direction::Outbound).unwrap();
    let stream = TcpStream::connect("self-signed.badssl.com:443").unwrap();
    // temporarily switch to nonblocking to allow us to construct the stream
    // without validating
    stream.set_nonblocking(true).unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("self-signed.badssl.com")
        .initialize(creds, stream)
        .unwrap();
    stream.get_ref().set_nonblocking(false).unwrap();
    assert!(stream.write(b"hi").is_err());
    assert!(stream.write(b"hi").is_err());
}<commit_msg>Make test a bit more robutst<commit_after>use std::io::{Read, Write};
use std::net::TcpStream;
use winapi;

use schannel_cred::{Direction, Protocol, Algorithm, SchannelCred};
use tls_stream;

#[test]
fn basic() {
    let creds = SchannelCred::builder().acquire(Direction::Outbound).unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut out = vec![];
    stream.read_to_end(&mut out).unwrap();
    assert!(out.starts_with(b"HTTP/1.0 200 OK"));
    assert!(out.ends_with(b""));
}

#[test]
fn invalid_algorithms() {
    let creds = SchannelCred::builder()
        .supported_algorithms(&[Algorithm::Rc2, Algorithm::Ecdsa])
        .acquire(Direction::Outbound);
    assert_eq!(creds.err().unwrap().raw_os_error().unwrap(),
               winapi::SEC_E_ALGORITHM_MISMATCH as i32);
}

#[test]
fn valid_algorithms() {
    let creds = SchannelCred::builder()
        .supported_algorithms(&[Algorithm::Aes128, Algorithm::Ecdsa])
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut out = vec![];
    stream.read_to_end(&mut out).unwrap();
    assert!(out.starts_with(b"HTTP/1.0 200 OK"));
    assert!(out.ends_with(b""));
}

#[test]
#[ignore] // google's inconsistent about disallowing sslv3
fn invalid_protocol() {
    let creds = SchannelCred::builder()
        .enabled_protocols(&[Protocol::Ssl3])
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::SEC_E_UNSUPPORTED_FUNCTION as i32);
}

#[test]
fn valid_protocol() {
    let creds = SchannelCred::builder()
        .enabled_protocols(&[Protocol::Tls12])
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut out = vec![];
    stream.read_to_end(&mut out).unwrap();
    assert!(out.starts_with(b"HTTP/1.0 200 OK"));
    assert!(out.ends_with(b""));
}

#[test]
fn expired_cert() {
    let creds = SchannelCred::builder()
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("expired.badssl.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("expired.badssl.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::CERT_E_EXPIRED as i32);
}

#[test]
fn self_signed_cert() {
    let creds = SchannelCred::builder()
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("self-signed.badssl.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("self-signed.badssl.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::CERT_E_UNTRUSTEDROOT as i32);
}

#[test]
fn wrong_host_cert() {
    let creds = SchannelCred::builder()
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("wrong.host.badssl.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("wrong.host.badssl.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::CERT_E_CN_NO_MATCH as i32);
}

#[test]
fn shutdown() {
    let creds = SchannelCred::builder().acquire(Direction::Outbound).unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.shutdown().unwrap();
}

#[test]
fn validation_failure_is_permanent() {
    let creds = SchannelCred::builder().acquire(Direction::Outbound).unwrap();
    let stream = TcpStream::connect("self-signed.badssl.com:443").unwrap();
    // temporarily switch to nonblocking to allow us to construct the stream
    // without validating
    stream.set_nonblocking(true).unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("self-signed.badssl.com")
        .initialize(creds, stream)
        .unwrap();
    stream.get_ref().set_nonblocking(false).unwrap();
    assert_eq!(stream.write(b"hi").err().unwrap().raw_os_error().unwrap(),
               winapi::CERT_E_UNTRUSTEDROOT as i32);
    assert_eq!(stream.write(b"hi").err().unwrap().raw_os_error().unwrap(),
               winapi::CERT_E_UNTRUSTEDROOT as i32);
}<|endoftext|>


<commit_before>use core::fmt::Debug;

#[cfg(feature = "chrono")]
use chrono;
#[cfg(feature = "chrono")]
use chrono::{Datelike, Local, TimeZone, Timelike};

/// A DOS compatible date.
///
/// Used by `DirEntry` time-related methods.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct Date {
    /// Full year - [1980, 2107]
    pub year: u16,
    /// Month of the year - [1, 12]
    pub month: u16,
    /// Day of the month - [1, 31]
    pub day: u16,
}

impl Date {
    pub(crate) fn decode(dos_date: u16) -> Self {
        let (year, month, day) = ((dos_date >> 9) + 1980, (dos_date >> 5) & 0xF, dos_date & 0x1F);
        Date { year, month, day }
    }

    pub(crate) fn encode(&self) -> u16 {
        ((self.year - 1980) << 9) | (self.month << 5) | self.day
    }
}

/// A DOS compatible time.
///
/// Used by `DirEntry` time-related methods.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct Time {
    /// Hours after midnight - [0, 23]
    pub hour: u16,
    /// Minutes after the hour - [0, 59]
    pub min: u16,
    /// Seconds after the minute - [0, 59]
    pub sec: u16,
    /// Milliseconds after the second - [0, 999]
    pub millis: u16,
}

impl Time {
    pub(crate) fn decode(dos_time: u16, dos_time_hi_res: u8) -> Self {
        let hour = dos_time >> 11;
        let min = (dos_time >> 5) & 0x3F;
        let sec = (dos_time & 0x1F) * 2 + (dos_time_hi_res as u16) / 2;
        let millis = (dos_time_hi_res as u16 % 100) * 10;
        Time { hour, min, sec, millis }
    }

    pub(crate) fn encode(&self) -> (u16, u8) {
        let dos_time = (self.hour << 11) | (self.min << 5) | (self.sec / 2);
        let dos_time_hi_res = ((self.millis / 100) + (self.sec % 2) * 100) as u8;
        (dos_time, dos_time_hi_res)
    }
}

/// A DOS compatible date and time.
///
/// Used by `DirEntry` time-related methods.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct DateTime {
    /// A date part
    pub date: Date,
    // A time part
    pub time: Time,
}

impl DateTime {
    pub(crate) fn decode(dos_date: u16, dos_time: u16, dos_time_hi_res: u8) -> Self {
        DateTime { date: Date::decode(dos_date), time: Time::decode(dos_time, dos_time_hi_res) }
    }
}

#[cfg(feature = "chrono")]
impl From<Date> for chrono::Date<Local> {
    fn from(date: Date) -> Self {
        Local.ymd(date.year as i32, date.month as u32, date.day as u32)
    }
}

#[cfg(feature = "chrono")]
impl From<DateTime> for chrono::DateTime<Local> {
    fn from(date_time: DateTime) -> Self {
        chrono::Date::<Local>::from(date_time.date).and_hms_milli(
            date_time.time.hour as u32,
            date_time.time.min as u32,
            date_time.time.sec as u32,
            date_time.time.millis as u32,
        )
    }
}

#[cfg(feature = "chrono")]
impl From<chrono::Date<Local>> for Date {
    fn from(date: chrono::Date<Local>) -> Self {
        Date { year: date.year() as u16, month: date.month() as u16, day: date.day() as u16 }
    }
}

#[cfg(feature = "chrono")]
impl From<chrono::DateTime<Local>> for DateTime {
    fn from(date_time: chrono::DateTime<Local>) -> Self {
        DateTime {
            date: Date::from(date_time.date()),
            time: Time {
                hour: date_time.hour() as u16,
                min: date_time.minute() as u16,
                sec: date_time.second() as u16,
                millis: (date_time.nanosecond() / 1_000_000) as u16,
            },
        }
    }
}

/// A current time and date provider.
///
/// Provides a custom implementation for a time resolution used when updating directory entry time fields.
/// Default implementation gets time from `chrono` crate if `chrono` feature is enabled.
/// Otherwise default implementation returns DOS minimal date-time (1980/1/1 0:00:00).
/// `TimeProvider` is specified by the `time_provider` property in `FsOptions` struct.
pub trait TimeProvider: Debug {
    fn get_current_date(&self) -> Date;
    fn get_current_date_time(&self) -> DateTime;
}

#[derive(Debug)]
pub(crate) struct DefaultTimeProvider {
    _dummy: (),
}

impl TimeProvider for DefaultTimeProvider {
    #[cfg(feature = "chrono")]
    fn get_current_date(&self) -> Date {
        Date::from(chrono::Local::now().date())
    }
    #[cfg(not(feature = "chrono"))]
    fn get_current_date(&self) -> Date {
        Date::decode(0)
    }

    #[cfg(feature = "chrono")]
    fn get_current_date_time(&self) -> DateTime {
        DateTime::from(chrono::Local::now())
    }
    #[cfg(not(feature = "chrono"))]
    fn get_current_date_time(&self) -> DateTime {
        DateTime::decode(0, 0, 0)
    }
}

pub(crate) static DEFAULT_TIME_PROVIDER: DefaultTimeProvider = DefaultTimeProvider { _dummy: () };
<commit_msg>Fix time encoding and decoding<commit_after>use core::fmt::Debug;

#[cfg(feature = "chrono")]
use chrono;
#[cfg(feature = "chrono")]
use chrono::{Datelike, Local, TimeZone, Timelike};

/// A DOS compatible date.
///
/// Used by `DirEntry` time-related methods.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct Date {
    /// Full year - [1980, 2107]
    pub year: u16,
    /// Month of the year - [1, 12]
    pub month: u16,
    /// Day of the month - [1, 31]
    pub day: u16,
}

impl Date {
    pub(crate) fn decode(dos_date: u16) -> Self {
        let (year, month, day) = ((dos_date >> 9) + 1980, (dos_date >> 5) & 0xF, dos_date & 0x1F);
        Date { year, month, day }
    }

    pub(crate) fn encode(&self) -> u16 {
        ((self.year - 1980) << 9) | (self.month << 5) | self.day
    }
}

/// A DOS compatible time.
///
/// Used by `DirEntry` time-related methods.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct Time {
    /// Hours after midnight - [0, 23]
    pub hour: u16,
    /// Minutes after the hour - [0, 59]
    pub min: u16,
    /// Seconds after the minute - [0, 59]
    pub sec: u16,
    /// Milliseconds after the second - [0, 999]
    pub millis: u16,
}

impl Time {
    pub(crate) fn decode(dos_time: u16, dos_time_hi_res: u8) -> Self {
        let hour = dos_time >> 11;
        let min = (dos_time >> 5) & 0x3F;
        let sec = (dos_time & 0x1F) * 2 + (dos_time_hi_res as u16) / 100;
        let millis = (dos_time_hi_res as u16 % 100) * 10;
        Time { hour, min, sec, millis }
    }

    pub(crate) fn encode(&self) -> (u16, u8) {
        let dos_time = (self.hour << 11) | (self.min << 5) | (self.sec / 2);
        let dos_time_hi_res = ((self.millis / 10) + (self.sec % 2) * 100) as u8;
        (dos_time, dos_time_hi_res)
    }
}

/// A DOS compatible date and time.
///
/// Used by `DirEntry` time-related methods.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct DateTime {
    /// A date part
    pub date: Date,
    // A time part
    pub time: Time,
}

impl DateTime {
    pub(crate) fn decode(dos_date: u16, dos_time: u16, dos_time_hi_res: u8) -> Self {
        DateTime { date: Date::decode(dos_date), time: Time::decode(dos_time, dos_time_hi_res) }
    }
}

#[cfg(feature = "chrono")]
impl From<Date> for chrono::Date<Local> {
    fn from(date: Date) -> Self {
        Local.ymd(date.year as i32, date.month as u32, date.day as u32)
    }
}

#[cfg(feature = "chrono")]
impl From<DateTime> for chrono::DateTime<Local> {
    fn from(date_time: DateTime) -> Self {
        chrono::Date::<Local>::from(date_time.date).and_hms_milli(
            date_time.time.hour as u32,
            date_time.time.min as u32,
            date_time.time.sec as u32,
            date_time.time.millis as u32,
        )
    }
}

#[cfg(feature = "chrono")]
impl From<chrono::Date<Local>> for Date {
    fn from(date: chrono::Date<Local>) -> Self {
        Date { year: date.year() as u16, month: date.month() as u16, day: date.day() as u16 }
    }
}

#[cfg(feature = "chrono")]
impl From<chrono::DateTime<Local>> for DateTime {
    fn from(date_time: chrono::DateTime<Local>) -> Self {
        DateTime {
            date: Date::from(date_time.date()),
            time: Time {
                hour: date_time.hour() as u16,
                min: date_time.minute() as u16,
                sec: date_time.second() as u16,
                millis: (date_time.nanosecond() / 1_000_000) as u16,
            },
        }
    }
}

/// A current time and date provider.
///
/// Provides a custom implementation for a time resolution used when updating directory entry time fields.
/// Default implementation gets time from `chrono` crate if `chrono` feature is enabled.
/// Otherwise default implementation returns DOS minimal date-time (1980/1/1 0:00:00).
/// `TimeProvider` is specified by the `time_provider` property in `FsOptions` struct.
pub trait TimeProvider: Debug {
    fn get_current_date(&self) -> Date;
    fn get_current_date_time(&self) -> DateTime;
}

#[derive(Debug)]
pub(crate) struct DefaultTimeProvider {
    _dummy: (),
}

impl TimeProvider for DefaultTimeProvider {
    #[cfg(feature = "chrono")]
    fn get_current_date(&self) -> Date {
        Date::from(chrono::Local::now().date())
    }
    #[cfg(not(feature = "chrono"))]
    fn get_current_date(&self) -> Date {
        Date::decode(0)
    }

    #[cfg(feature = "chrono")]
    fn get_current_date_time(&self) -> DateTime {
        DateTime::from(chrono::Local::now())
    }
    #[cfg(not(feature = "chrono"))]
    fn get_current_date_time(&self) -> DateTime {
        DateTime::decode(0, 0, 0)
    }
}

pub(crate) static DEFAULT_TIME_PROVIDER: DefaultTimeProvider = DefaultTimeProvider { _dummy: () };

#[cfg(test)]
mod tests {
    use super::{Date, Time};

    #[test]
    fn date_encode_decode() {
        let d = Date {
            year: 2055,
            month: 7,
            day: 23
        };
        assert_eq!(d, Date::decode(d.encode()));
    }

    #[test]
    fn time_encode_decode() {
        let t1 = Time {
            hour: 15,
            min: 3,
            sec: 29,
            millis: 990,
        };
        let t2 = Time {
            sec: 18,
            .. t1
        };
        let t3 = Time {
            millis: 40,
            .. t1
        };
        let (x1, y1) = t1.encode();
        let (x2, y2) = t2.encode();
        let (x3, y3) = t3.encode();
        assert_eq!(t1, Time::decode(x1, y1));
        assert_eq!(t2, Time::decode(x2, y2));
        assert_eq!(t3, Time::decode(x3, y3));
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::cmp::Ordering;
use std::ffi::CString;
use std::ops::Range;
use std::marker;
use std::path::Path;
use std::str;
use libc;

use {raw, Oid, Repository, Error, Object, ObjectType};
use util::{Binding, IntoCString};

/// A structure to represent a git [tree][1]
///
/// [1]: http://git-scm.com/book/en/Git-Internals-Git-Objects
pub struct Tree<'repo> {
    raw: *mut raw::git_tree,
    _marker: marker::PhantomData<Object<'repo>>,
}

/// A structure representing an entry inside of a tree. An entry is borrowed
/// from a tree.
pub struct TreeEntry<'tree> {
    raw: *mut raw::git_tree_entry,
    owned: bool,
    _marker: marker::PhantomData<&'tree raw::git_tree_entry>,
}

/// An iterator over the entries in a tree.
pub struct TreeIter<'tree> {
    range: Range<usize>,
    tree: &'tree Tree<'tree>,
}

impl<'repo> Tree<'repo> {
    /// Get the id (SHA1) of a repository object
    pub fn id(&self) -> Oid {
        unsafe { Binding::from_raw(raw::git_tree_id(&*self.raw)) }
    }

    /// Get the number of entries listed in this tree.
    pub fn len(&self) -> usize {
        unsafe { raw::git_tree_entrycount(&*self.raw) as usize }
    }

    /// Returns an iterator over the entries in this tree.
    pub fn iter(&self) -> TreeIter {
        TreeIter { range: 0..self.len(), tree: self }
    }

    /// Lookup a tree entry by SHA value.
    pub fn get_id(&self, id: Oid) -> Option<TreeEntry> {
        unsafe {
            let ptr = raw::git_tree_entry_byid(&*self.raw(), &*id.raw());
            if ptr.is_null() {
                None
            } else {
                Some(TreeEntry::from_raw_const(ptr))
            }
        }
    }

    /// Lookup a tree entry by its position in the tree
    pub fn get(&self, n: usize) -> Option<TreeEntry> {
        unsafe {
            let ptr = raw::git_tree_entry_byindex(&*self.raw(),
                                                  n as libc::size_t);
            if ptr.is_null() {
                None
            } else {
                Some(TreeEntry::from_raw_const(ptr))
            }
        }
    }

    /// Lookup a tree entry by its filename
    pub fn get_name(&self, filename: &str) -> Option<TreeEntry> {
        let filename = CString::new(filename).unwrap();
        unsafe {
            let ptr = call!(raw::git_tree_entry_byname(&*self.raw(), filename));
            if ptr.is_null() {
                None
            } else {
                Some(TreeEntry::from_raw_const(ptr))
            }
        }
    }

    /// Retrieve a tree entry contained in a tree or in any of its subtrees,
    /// given its relative path.
    pub fn get_path(&self, path: &Path) -> Result<TreeEntry<'static>, Error> {
        let path = try!(path.into_c_string());
        let mut ret = 0 as *mut raw::git_tree_entry;
        unsafe {
            try_call!(raw::git_tree_entry_bypath(&mut ret, &*self.raw(), path));
            Ok(Binding::from_raw(ret))
        }
    }
}

impl<'repo> Binding for Tree<'repo> {
    type Raw = *mut raw::git_tree;

    unsafe fn from_raw(raw: *mut raw::git_tree) -> Tree<'repo> {
        Tree { raw: raw, _marker: marker::PhantomData }
    }
    fn raw(&self) -> *mut raw::git_tree { self.raw }
}

impl<'repo> Drop for Tree<'repo> {
    fn drop(&mut self) {
        unsafe { raw::git_tree_free(self.raw) }
    }
}

impl<'tree> TreeEntry<'tree> {
    /// Create a new tree entry from the raw pointer provided.
    ///
    /// The lifetime of the entry is tied to the tree provided and the function
    /// is unsafe because the validity of the pointer cannot be guaranteed.
    unsafe fn from_raw_const(raw: *const raw::git_tree_entry)
                                 -> TreeEntry<'tree> {
        TreeEntry {
            raw: raw as *mut raw::git_tree_entry,
            owned: false,
            _marker: marker::PhantomData,
        }
    }

    /// Get the id of the object pointed by the entry
    pub fn id(&self) -> Oid {
        unsafe { Binding::from_raw(raw::git_tree_entry_id(&*self.raw)) }
    }

    /// Get the filename of a tree entry
    ///
    /// Returns `None` if the name is not valid utf-8
    pub fn name(&self) -> Option<&str> {
        str::from_utf8(self.name_bytes()).ok()
    }

    /// Get the filename of a tree entry
    pub fn name_bytes(&self) -> &[u8] {
        unsafe {
            ::opt_bytes(self, raw::git_tree_entry_name(&*self.raw())).unwrap()
        }
    }

    /// Convert a tree entry to the object it points to.
    pub fn to_object<'a>(&self, repo: &'a Repository)
                         -> Result<Object<'a>, Error> {
        let mut ret = 0 as *mut raw::git_object;
        unsafe {
            try_call!(raw::git_tree_entry_to_object(&mut ret, repo.raw(),
                                                    &*self.raw()));
            Ok(Binding::from_raw(ret))
        }
    }

    /// Get the type of the object pointed by the entry
    pub fn kind(&self) -> Option<ObjectType> {
        ObjectType::from_raw(unsafe { raw::git_tree_entry_type(&*self.raw) })
    }

    /// Get the UNIX file attributes of a tree entry
    pub fn filemode(&self) -> i32 {
        unsafe { raw::git_tree_entry_filemode(&*self.raw) as i32 }
    }

    /// Get the raw UNIX file attributes of a tree entry
    pub fn filemode_raw(&self) -> i32 {
        unsafe { raw::git_tree_entry_filemode_raw(&*self.raw) as i32 }
    }

    /// Clone the underlying raw tree entry
    pub fn to_owned(&self) -> TreeEntry<'static> {
        unsafe {
            let me = mem::transmute::<&TreeEntry<'tree>, &TreeEntry<'static>>(self);
            me.clone()
        }
    }
}

impl<'a> Binding for TreeEntry<'a> {
    type Raw = *mut raw::git_tree_entry;
    unsafe fn from_raw(raw: *mut raw::git_tree_entry) -> TreeEntry<'a> {
        TreeEntry {
            raw: raw,
            owned: true,
            _marker: marker::PhantomData,
        }
    }
    fn raw(&self) -> *mut raw::git_tree_entry { self.raw }
}

impl<'a> Clone for TreeEntry<'a> {
    fn clone(&self) -> TreeEntry<'a> {
        let mut ret = 0 as *mut raw::git_tree_entry;
        unsafe {
            assert_eq!(raw::git_tree_entry_dup(&mut ret, &*self.raw()), 0);
            Binding::from_raw(ret)
        }
    }
}

impl<'a> PartialOrd for TreeEntry<'a> {
    fn partial_cmp(&self, other: &TreeEntry<'a>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl<'a> Ord for TreeEntry<'a> {
    fn cmp(&self, other: &TreeEntry<'a>) -> Ordering {
        match unsafe { raw::git_tree_entry_cmp(&*self.raw(), &*other.raw()) } {
            0 => Ordering::Equal,
            n if n < 0 => Ordering::Less,
            _ => Ordering::Greater,
        }
    }
}

impl<'a> PartialEq for TreeEntry<'a> {
    fn eq(&self, other: &TreeEntry<'a>) -> bool {
        self.cmp(other) == Ordering::Equal
    }
}
impl<'a> Eq for TreeEntry<'a> {}

impl<'a> Drop for TreeEntry<'a> {
    fn drop(&mut self) {
        if self.owned {
            unsafe { raw::git_tree_entry_free(self.raw) }
        }
    }
}

impl<'tree> Iterator for TreeIter<'tree> {
    type Item = TreeEntry<'tree>;
    fn next(&mut self) -> Option<TreeEntry<'tree>> {
        self.range.next().and_then(|i| self.tree.get(i))
    }
    fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
}
impl<'tree> DoubleEndedIterator for TreeIter<'tree> {
    fn next_back(&mut self) -> Option<TreeEntry<'tree>> {
        self.range.next_back().and_then(|i| self.tree.get(i))
    }
}
impl<'tree> ExactSizeIterator for TreeIter<'tree> {}

#[cfg(test)]
mod tests {
    use {Repository,Tree,TreeEntry,ObjectType,Object};
    use tempdir::TempDir;
    use std::fs::File;
    use std::io::prelude::*;
    use std::path::Path;

    pub struct TestTreeIter<'a> {
        entries: Vec<TreeEntry<'a>>,
        repo: &'a Repository,
    }

    impl<'a> Iterator for TestTreeIter<'a> {
        type Item = TreeEntry<'a>;

        fn next(&mut self) -> Option<TreeEntry<'a> > {
            if self.entries.is_empty() {
                None
            } else {
                let entry = self.entries.remove(0);

                match entry.kind() {
                    Some(ObjectType::Tree) => {
                        let obj: Object<'a> = entry.to_object(self.repo).unwrap();

                        let tree: &Tree<'a> = obj.as_tree().unwrap();

                        for entry in tree.iter() {
                            self.entries.push(entry.to_owned());
                        }
                    }
                    _ => {}
                }

                Some(entry)
            }
        }
    }

    fn tree_iter<'tree,'repo:'tree>(tree: &'tree Tree<'repo>, repo: &'repo Repository) -> TestTreeIter<'repo> {
        let mut initial = vec![];

        for entry in tree.iter() {
            initial.push(entry.to_owned());
        }

        TestTreeIter {
            entries: initial,
            repo: repo,
        }
    }

    #[test]
    fn smoke_tree_iter() {
        let (td, repo) = ::test::repo_init();

        setup_repo(&td, &repo);

        let head = repo.head().unwrap();
        let target = head.target().unwrap();
        let commit = repo.find_commit(target).unwrap();

        let tree = repo.find_tree(commit.tree_id()).unwrap();
        assert_eq!(tree.id(), commit.tree_id());
        assert_eq!(tree.len(), 1);

//        let mut entries = vec![];

        for entry in tree_iter(&tree, &repo) {
            println!("iter entry {:?}", entry.name());
        }
    }

    fn setup_repo(td: &TempDir, repo: &Repository) {
        let mut index = repo.index().unwrap();
        File::create(&td.path().join("foo")).unwrap().write_all(b"foo").unwrap();
        index.add_path(Path::new("foo")).unwrap();
        let id = index.write_tree().unwrap();
        let sig = repo.signature().unwrap();
        let tree = repo.find_tree(id).unwrap();
        let parent = repo.find_commit(repo.head().unwrap().target()
                                      .unwrap()).unwrap();
        repo.commit(Some("HEAD"), &sig, &sig, "another commit",
                    &tree, &[&parent]).unwrap();
    }

    #[test]
    fn smoke() {
        let (td, repo) = ::test::repo_init();

        setup_repo(&td, &repo);

        let head = repo.head().unwrap();
        let target = head.target().unwrap();
        let commit = repo.find_commit(target).unwrap();

        let tree = repo.find_tree(commit.tree_id()).unwrap();
        assert_eq!(tree.id(), commit.tree_id());
        assert_eq!(tree.len(), 1);
        let e1 = tree.get(0).unwrap();
        assert!(e1 == tree.get_id(e1.id()).unwrap());
        assert!(e1 == tree.get_name("foo").unwrap());
        assert!(e1 == tree.get_path(Path::new("foo")).unwrap());
        assert_eq!(e1.name(), Some("foo"));
        e1.to_object(&repo).unwrap();

        repo.find_object(commit.tree_id(), None).unwrap().as_tree().unwrap();
    }
}
<commit_msg>Wrap a few lines<commit_after>use std::mem;
use std::cmp::Ordering;
use std::ffi::CString;
use std::ops::Range;
use std::marker;
use std::path::Path;
use std::str;
use libc;

use {raw, Oid, Repository, Error, Object, ObjectType};
use util::{Binding, IntoCString};

/// A structure to represent a git [tree][1]
///
/// [1]: http://git-scm.com/book/en/Git-Internals-Git-Objects
pub struct Tree<'repo> {
    raw: *mut raw::git_tree,
    _marker: marker::PhantomData<Object<'repo>>,
}

/// A structure representing an entry inside of a tree. An entry is borrowed
/// from a tree.
pub struct TreeEntry<'tree> {
    raw: *mut raw::git_tree_entry,
    owned: bool,
    _marker: marker::PhantomData<&'tree raw::git_tree_entry>,
}

/// An iterator over the entries in a tree.
pub struct TreeIter<'tree> {
    range: Range<usize>,
    tree: &'tree Tree<'tree>,
}

impl<'repo> Tree<'repo> {
    /// Get the id (SHA1) of a repository object
    pub fn id(&self) -> Oid {
        unsafe { Binding::from_raw(raw::git_tree_id(&*self.raw)) }
    }

    /// Get the number of entries listed in this tree.
    pub fn len(&self) -> usize {
        unsafe { raw::git_tree_entrycount(&*self.raw) as usize }
    }

    /// Returns an iterator over the entries in this tree.
    pub fn iter(&self) -> TreeIter {
        TreeIter { range: 0..self.len(), tree: self }
    }

    /// Lookup a tree entry by SHA value.
    pub fn get_id(&self, id: Oid) -> Option<TreeEntry> {
        unsafe {
            let ptr = raw::git_tree_entry_byid(&*self.raw(), &*id.raw());
            if ptr.is_null() {
                None
            } else {
                Some(TreeEntry::from_raw_const(ptr))
            }
        }
    }

    /// Lookup a tree entry by its position in the tree
    pub fn get(&self, n: usize) -> Option<TreeEntry> {
        unsafe {
            let ptr = raw::git_tree_entry_byindex(&*self.raw(),
                                                  n as libc::size_t);
            if ptr.is_null() {
                None
            } else {
                Some(TreeEntry::from_raw_const(ptr))
            }
        }
    }

    /// Lookup a tree entry by its filename
    pub fn get_name(&self, filename: &str) -> Option<TreeEntry> {
        let filename = CString::new(filename).unwrap();
        unsafe {
            let ptr = call!(raw::git_tree_entry_byname(&*self.raw(), filename));
            if ptr.is_null() {
                None
            } else {
                Some(TreeEntry::from_raw_const(ptr))
            }
        }
    }

    /// Retrieve a tree entry contained in a tree or in any of its subtrees,
    /// given its relative path.
    pub fn get_path(&self, path: &Path) -> Result<TreeEntry<'static>, Error> {
        let path = try!(path.into_c_string());
        let mut ret = 0 as *mut raw::git_tree_entry;
        unsafe {
            try_call!(raw::git_tree_entry_bypath(&mut ret, &*self.raw(), path));
            Ok(Binding::from_raw(ret))
        }
    }
}

impl<'repo> Binding for Tree<'repo> {
    type Raw = *mut raw::git_tree;

    unsafe fn from_raw(raw: *mut raw::git_tree) -> Tree<'repo> {
        Tree { raw: raw, _marker: marker::PhantomData }
    }
    fn raw(&self) -> *mut raw::git_tree { self.raw }
}

impl<'repo> Drop for Tree<'repo> {
    fn drop(&mut self) {
        unsafe { raw::git_tree_free(self.raw) }
    }
}

impl<'tree> TreeEntry<'tree> {
    /// Create a new tree entry from the raw pointer provided.
    ///
    /// The lifetime of the entry is tied to the tree provided and the function
    /// is unsafe because the validity of the pointer cannot be guaranteed.
    unsafe fn from_raw_const(raw: *const raw::git_tree_entry)
                                 -> TreeEntry<'tree> {
        TreeEntry {
            raw: raw as *mut raw::git_tree_entry,
            owned: false,
            _marker: marker::PhantomData,
        }
    }

    /// Get the id of the object pointed by the entry
    pub fn id(&self) -> Oid {
        unsafe { Binding::from_raw(raw::git_tree_entry_id(&*self.raw)) }
    }

    /// Get the filename of a tree entry
    ///
    /// Returns `None` if the name is not valid utf-8
    pub fn name(&self) -> Option<&str> {
        str::from_utf8(self.name_bytes()).ok()
    }

    /// Get the filename of a tree entry
    pub fn name_bytes(&self) -> &[u8] {
        unsafe {
            ::opt_bytes(self, raw::git_tree_entry_name(&*self.raw())).unwrap()
        }
    }

    /// Convert a tree entry to the object it points to.
    pub fn to_object<'a>(&self, repo: &'a Repository)
                         -> Result<Object<'a>, Error> {
        let mut ret = 0 as *mut raw::git_object;
        unsafe {
            try_call!(raw::git_tree_entry_to_object(&mut ret, repo.raw(),
                                                    &*self.raw()));
            Ok(Binding::from_raw(ret))
        }
    }

    /// Get the type of the object pointed by the entry
    pub fn kind(&self) -> Option<ObjectType> {
        ObjectType::from_raw(unsafe { raw::git_tree_entry_type(&*self.raw) })
    }

    /// Get the UNIX file attributes of a tree entry
    pub fn filemode(&self) -> i32 {
        unsafe { raw::git_tree_entry_filemode(&*self.raw) as i32 }
    }

    /// Get the raw UNIX file attributes of a tree entry
    pub fn filemode_raw(&self) -> i32 {
        unsafe { raw::git_tree_entry_filemode_raw(&*self.raw) as i32 }
    }

    /// Clone the underlying raw tree entry
    pub fn to_owned(&self) -> TreeEntry<'static> {
        unsafe {
            let me = mem::transmute::<&TreeEntry<'tree>, &TreeEntry<'static>>(self);
            me.clone()
        }
    }
}

impl<'a> Binding for TreeEntry<'a> {
    type Raw = *mut raw::git_tree_entry;
    unsafe fn from_raw(raw: *mut raw::git_tree_entry) -> TreeEntry<'a> {
        TreeEntry {
            raw: raw,
            owned: true,
            _marker: marker::PhantomData,
        }
    }
    fn raw(&self) -> *mut raw::git_tree_entry { self.raw }
}

impl<'a> Clone for TreeEntry<'a> {
    fn clone(&self) -> TreeEntry<'a> {
        let mut ret = 0 as *mut raw::git_tree_entry;
        unsafe {
            assert_eq!(raw::git_tree_entry_dup(&mut ret, &*self.raw()), 0);
            Binding::from_raw(ret)
        }
    }
}

impl<'a> PartialOrd for TreeEntry<'a> {
    fn partial_cmp(&self, other: &TreeEntry<'a>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl<'a> Ord for TreeEntry<'a> {
    fn cmp(&self, other: &TreeEntry<'a>) -> Ordering {
        match unsafe { raw::git_tree_entry_cmp(&*self.raw(), &*other.raw()) } {
            0 => Ordering::Equal,
            n if n < 0 => Ordering::Less,
            _ => Ordering::Greater,
        }
    }
}

impl<'a> PartialEq for TreeEntry<'a> {
    fn eq(&self, other: &TreeEntry<'a>) -> bool {
        self.cmp(other) == Ordering::Equal
    }
}
impl<'a> Eq for TreeEntry<'a> {}

impl<'a> Drop for TreeEntry<'a> {
    fn drop(&mut self) {
        if self.owned {
            unsafe { raw::git_tree_entry_free(self.raw) }
        }
    }
}

impl<'tree> Iterator for TreeIter<'tree> {
    type Item = TreeEntry<'tree>;
    fn next(&mut self) -> Option<TreeEntry<'tree>> {
        self.range.next().and_then(|i| self.tree.get(i))
    }
    fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
}
impl<'tree> DoubleEndedIterator for TreeIter<'tree> {
    fn next_back(&mut self) -> Option<TreeEntry<'tree>> {
        self.range.next_back().and_then(|i| self.tree.get(i))
    }
}
impl<'tree> ExactSizeIterator for TreeIter<'tree> {}

#[cfg(test)]
mod tests {
    use {Repository,Tree,TreeEntry,ObjectType,Object};
    use tempdir::TempDir;
    use std::fs::File;
    use std::io::prelude::*;
    use std::path::Path;

    pub struct TestTreeIter<'a> {
        entries: Vec<TreeEntry<'a>>,
        repo: &'a Repository,
    }

    impl<'a> Iterator for TestTreeIter<'a> {
        type Item = TreeEntry<'a>;

        fn next(&mut self) -> Option<TreeEntry<'a> > {
            if self.entries.is_empty() {
                None
            } else {
                let entry = self.entries.remove(0);

                match entry.kind() {
                    Some(ObjectType::Tree) => {
                        let obj: Object<'a> = entry.to_object(self.repo).unwrap();

                        let tree: &Tree<'a> = obj.as_tree().unwrap();

                        for entry in tree.iter() {
                            self.entries.push(entry.to_owned());
                        }
                    }
                    _ => {}
                }

                Some(entry)
            }
        }
    }

    fn tree_iter<'repo>(tree: &Tree<'repo>, repo: &'repo Repository)
                        -> TestTreeIter<'repo> {
        let mut initial = vec![];

        for entry in tree.iter() {
            initial.push(entry.to_owned());
        }

        TestTreeIter {
            entries: initial,
            repo: repo,
        }
    }

    #[test]
    fn smoke_tree_iter() {
        let (td, repo) = ::test::repo_init();

        setup_repo(&td, &repo);

        let head = repo.head().unwrap();
        let target = head.target().unwrap();
        let commit = repo.find_commit(target).unwrap();

        let tree = repo.find_tree(commit.tree_id()).unwrap();
        assert_eq!(tree.id(), commit.tree_id());
        assert_eq!(tree.len(), 1);

        for entry in tree_iter(&tree, &repo) {
            println!("iter entry {:?}", entry.name());
        }
    }

    fn setup_repo(td: &TempDir, repo: &Repository) {
        let mut index = repo.index().unwrap();
        File::create(&td.path().join("foo")).unwrap().write_all(b"foo").unwrap();
        index.add_path(Path::new("foo")).unwrap();
        let id = index.write_tree().unwrap();
        let sig = repo.signature().unwrap();
        let tree = repo.find_tree(id).unwrap();
        let parent = repo.find_commit(repo.head().unwrap().target()
                                      .unwrap()).unwrap();
        repo.commit(Some("HEAD"), &sig, &sig, "another commit",
                    &tree, &[&parent]).unwrap();
    }

    #[test]
    fn smoke() {
        let (td, repo) = ::test::repo_init();

        setup_repo(&td, &repo);

        let head = repo.head().unwrap();
        let target = head.target().unwrap();
        let commit = repo.find_commit(target).unwrap();

        let tree = repo.find_tree(commit.tree_id()).unwrap();
        assert_eq!(tree.id(), commit.tree_id());
        assert_eq!(tree.len(), 1);
        let e1 = tree.get(0).unwrap();
        assert!(e1 == tree.get_id(e1.id()).unwrap());
        assert!(e1 == tree.get_name("foo").unwrap());
        assert!(e1 == tree.get_path(Path::new("foo")).unwrap());
        assert_eq!(e1.name(), Some("foo"));
        e1.to_object(&repo).unwrap();

        repo.find_object(commit.tree_id(), None).unwrap().as_tree().unwrap();
    }
}
<|endoftext|>