<commit_before>//! Interpolation functions and derivatives for geometric shapes (elements)
//!
//! # Definitions
//!
//! Here, we consider the following dimensions:
//!
//! * `space_ndim` -- is the number of dimensions of the space under study (2 or 3)
//! * `geo_ndim` -- is the number of dimensions of the geometry element (shape).
//!                  For instance, a line in the 2D space has `geo_ndim = 1` and
//!                  `space_ndim = 2`. Another example: a triangle in the 3D space
//!                  has `geo_ndim = 2` and `space_ndim = 3`.
//! * `local` -- refers to a numbering scheme for the nodes of the shape (or element)
//! * `global` -- refers to a numbering scheme applied for the whole mesh
//! * `spatial (real) space` -- is the "real" space mapped by the x₀,x₁,x₂ coordinates
//! * `reference (natural) space` -- is the "virtual" space mapped by the ξ₀,ξ₁,ξ₂ coordinates
//!
//! We also consider the following counting variables:
//!
//! * `nnode` -- (local) number of points (aka nodes) that define the shape/element.
//! * `npoint` -- (global) number of points in the whole mesh; not used in this module
//!               but important to remember
//! * `nedge` -- number of edges on the shape (2D or 3D)
//! * `nface` -- number of faces on the shape (3D only)
//! * `edge_nnode` -- number of points/nodes that define the edge
//! * `face_nnode` -- number of points/nodes that define the face
//! * `face_nedge` -- number of edges on the face
//!
//! # Isoparametric formulation
//!
//! The isoparametric formulation establishes that we can calculate the coordinates `x(ξ)`
//! within the shape/element from the shape functions `Nᵐ(ξ)` and the coordinates at each
//! node by using the formula:
//!
//! ```text
//! → →         →  →
//! x(ξ) = Σ Nᵐ(ξ) xᵐ
//!        m
//! ```
//!
//! where `x` is the (space_ndim) vector of real coordinates, `ξ` is the (geo_ndim)
//! vector of reference coordinates, `Nᵐ` are the (nnode) interpolation functions,
//! and `xᵐ` are the (nnode) coordinates of each m-node of the geometric shape.
//!
//! Given an (nnode,space_ndim) **matrix** of coordinates `X`, we can calculate the
//! (space_ndim) **vector** of coordinates `x` by means of
//!
//! ```text
//! x = Xᵀ ⋅ N
//! ```
//!
//! where `N` is an (nnode) **vector** formed with all `Nᵐ` values.
//!
//! # Derivatives on the reference space and gradients on the real space
//!
//! ## General case with `geo_ndim == space_ndim`
//!
//! If `geo_ndim == space_ndim`, we define the Jacobian tensor as
//!
//! ```text
//!         →
//!   →    dx     →    →
//! J(ξ) = —— = Σ xᵐ ⊗ Lᵐ
//!         →   m
//!        dξ
//! ```
//!
//! where
//!
//! ```text
//!             →
//! →  →    dNᵐ(ξ)
//! Lᵐ(ξ) = ——————
//!            →
//!           dξ
//! ```
//!
//! are the derivatives of each interpolation function `Nm` with respect to the
//! reference coordinate. `Lm` are (geo_ndim) vectors and can be organized in
//! an (nnode,geo_ndim) matrix `L` of "local" derivatives.
//!
//! We can write the Jacobian in matrix notation as follows
//!
//! ```text
//! J = Xᵀ · L
//! ```
//!
//! where X is the (nnode,space_ndim) matrix of coordinates and L is the (nnode,geo_ndim) matrix.
//!
//! We define the gradient of interpolation functions (i.e., derivatives of interpolation
//! functions w.r.t real coordinates) by means of
//!
//! ```text
//!             →
//! →  →    dNᵐ(ξ)
//! Gᵐ(ξ) = ——————
//!            →
//!           dx
//! ```
//!
//! which can be organized in an (nnode,space_ndim) matrix `G`.
//!
//! The inverse Jacobian allows us to determine the gradient vectors G as follows
//!
//! ```text
//! →       →  →        →
//! Gᵐ(ξ) = Lᵐ(ξ) · J⁻¹(ξ)
//! ```
//!
//! Or, in matrix notation,
//!
//! ```text
//! G = L · J⁻¹
//! ```
//!
//! where G is an (nnode,space_ndim) matrix.
//!
//! ## Line in multi-dimensions (geo_ndim == 1 and space_ndim > 1)
//!
//! In this case, the Jacobian equals the (space_ndim,1) base vector `g1` tangent
//! to the line element, i.e.,
//!
//! ```text
//!                          →
//! →    →     →            dx
//! J := Jline(ξ) = g₁(ξ) = —— = Xᵀ · L
//!                         dξ
//! ```
//!
//! We also consider a parametric coordinate `ℓ` which varies
//! from 0 to `ℓ_max` (the length of the line) according to
//!
//! ```text
//!                ℓ_max
//! ℓ(ξ) = (1 + ξ) —————
//!                  2
//!
//!        2 · ℓ
//! ξ(ℓ) = ————— - 1
//!        ℓ_max
//! ```
//!
//! ```text
//! 0 ≤ ℓ ≤ ℓ_max
//!
//! -1 ≤ ξ ≤ +1
//! ```

mod enums;
mod hex20;
mod hex8;
mod lin2;
mod lin3;
mod lin4;
mod lin5;
mod qua12;
mod qua16;
mod qua17;
mod qua4;
mod qua8;
mod qua9;
mod shape;
mod state_of_shape;
mod tet10;
mod tet4;
mod tri10;
mod tri15;
mod tri3;
mod tri6;
pub use crate::shapes::enums::*;
pub use crate::shapes::hex20::*;
pub use crate::shapes::hex8::*;
pub use crate::shapes::lin2::*;
pub use crate::shapes::lin3::*;
pub use crate::shapes::lin4::*;
pub use crate::shapes::lin5::*;
pub use crate::shapes::qua12::*;
pub use crate::shapes::qua16::*;
pub use crate::shapes::qua17::*;
pub use crate::shapes::qua4::*;
pub use crate::shapes::qua8::*;
pub use crate::shapes::qua9::*;
pub use crate::shapes::shape::*;
pub use crate::shapes::state_of_shape::*;
pub use crate::shapes::tet10::*;
pub use crate::shapes::tet4::*;
pub use crate::shapes::tri10::*;
pub use crate::shapes::tri15::*;
pub use crate::shapes::tri3::*;
pub use crate::shapes::tri6::*;
<commit_msg>Improve doc<commit_after>//! Interpolation functions and derivatives for geometric shapes (elements)
//!
//! # Definitions
//!
//! Here, we consider the following dimensions:
//!
//! * `space_ndim` -- is the number of dimensions of the space under study (2 or 3)
//! * `geo_ndim` -- is the number of dimensions of the geometry element (shape).
//!                  For instance, a line in the 2D space has `geo_ndim = 1` and
//!                  `space_ndim = 2`. Another example: a triangle in the 3D space
//!                  has `geo_ndim = 2` and `space_ndim = 3`.
//! * `local` -- refers to a numbering scheme for the nodes of the shape (or element)
//! * `global` -- refers to a numbering scheme applied for the whole mesh
//! * `spatial (real) space` -- is the "real" space mapped by the x₀,x₁,x₂ coordinates (see figure below)
//! * `reference (natural) space` -- is the "virtual" space mapped by the ξ₀,ξ₁,ξ₂ coordinates (see figure below)
//!
//! ![Real and reference space mapping](https://github.com/cpmech/gemlab/raw/main/data/figures/mapping-real-to-reference.png)
//!
//! We also consider the following counting variables:
//!
//! * `nnode` -- (local) number of points (aka nodes) that define the shape/element.
//! * `npoint` -- (global) number of points in the whole mesh; not used in this module
//!               but important to remember
//! * `nedge` -- number of edges on the shape (2D or 3D)
//! * `nface` -- number of faces on the shape (3D only)
//! * `edge_nnode` -- number of points/nodes that define the edge
//! * `face_nnode` -- number of points/nodes that define the face
//! * `face_nedge` -- number of edges on the face
//!
//! # Isoparametric formulation
//!
//! The isoparametric formulation establishes that we can calculate the coordinates `x(ξ)`
//! within the shape/element from the shape functions `Nᵐ(ξ)` and the coordinates at each
//! node by using the formula:
//!
//! ```text
//! → →         →  →
//! x(ξ) = Σ Nᵐ(ξ) xᵐ
//!        m
//! ```
//!
//! where `x` is the (space_ndim) vector of real coordinates, `ξ` is the (geo_ndim)
//! vector of reference coordinates, `Nᵐ` are the (nnode) interpolation functions,
//! and `xᵐ` are the (nnode) coordinates of each m-node of the geometric shape.
//!
//! Given an (nnode,space_ndim) **matrix** of coordinates `X`, we can calculate the
//! (space_ndim) **vector** of coordinates `x` by means of
//!
//! ```text
//! x = Xᵀ ⋅ N
//! ```
//!
//! where `N` is an (nnode) **vector** formed with all `Nᵐ` values.
//!
//! # Derivatives on the reference space and gradients on the real space
//!
//! Here, we consider two cases:
//!
//! * General case with geo_ndim == space_ndim; and
//! * Line in multi-dimensions with geo_ndim == 1 and space_ndim > 1.
//!
//! ## General case with geo_ndim == space_ndim
//!
//! If `geo_ndim == space_ndim`, we define the Jacobian tensor as
//!
//! ```text
//!         →
//!   →    dx     →    →
//! J(ξ) = —— = Σ xᵐ ⊗ Lᵐ
//!         →   m
//!        dξ
//! ```
//!
//! where
//!
//! ```text
//!             →
//! →  →    dNᵐ(ξ)
//! Lᵐ(ξ) = ——————
//!            →
//!           dξ
//! ```
//!
//! are the derivatives of each interpolation function `Nᵐ` with respect to the
//! reference coordinate. `Lᵐ` are (geo_ndim) vectors and can be organized in
//! an (nnode,geo_ndim) matrix `L` of **local** derivatives.
//!
//! We can write the Jacobian in matrix notation as follows
//!
//! ```text
//! J = Xᵀ · L
//! ```
//!
//! where `X` is the (nnode,space_ndim) matrix of coordinates and `L` is the (nnode,geo_ndim) matrix.
//!
//! Next, we define the gradient of interpolation functions (i.e., derivatives of interpolation
//! functions w.r.t real coordinates) by means of
//!
//! ```text
//!             →
//! →  →    dNᵐ(ξ)
//! Gᵐ(ξ) = ——————
//!            →
//!           dx
//! ```
//!
//! which can be organized in an (nnode,space_ndim) matrix `G`.
//!
//! The inverse Jacobian allows us to determine the gradient vectors `G` as follows
//!
//! ```text
//! →       →  →        →
//! Gᵐ(ξ) = Lᵐ(ξ) · J⁻¹(ξ)
//! ```
//!
//! Or, in matrix notation,
//!
//! ```text
//! G = L · J⁻¹
//! ```
//!
//! where `G` is an (nnode,space_ndim) matrix.
//!
//! ## Line in multi-dimensions with geo_ndim == 1 and space_ndim > 1
//!
//! In this case, the Jacobian equals the (space_ndim,1) base vector `g₁` which
//! is tangent to the line element, i.e.,
//!
//! ```text
//!                          →
//! →    →     →            dx
//! J := Jline(ξ) = g₁(ξ) = —— = Xᵀ · L
//!                         dξ
//! ```
//!
//! We also consider a parametric coordinate `ℓ` which varies
//! from `0` to `ℓ_max` (the length of the line) according to
//!
//! ```text
//!                ℓ_max
//! ℓ(ξ) = (1 + ξ) —————
//!                  2
//!
//!        2 · ℓ
//! ξ(ℓ) = ————— - 1
//!        ℓ_max
//! ```
//!
//! Note that:
//!
//! ```text
//! 0 ≤ ℓ ≤ ℓ_max
//!
//! -1 ≤ ξ ≤ +1
//! ```

mod enums;
mod hex20;
mod hex8;
mod lin2;
mod lin3;
mod lin4;
mod lin5;
mod qua12;
mod qua16;
mod qua17;
mod qua4;
mod qua8;
mod qua9;
mod shape;
mod state_of_shape;
mod tet10;
mod tet4;
mod tri10;
mod tri15;
mod tri3;
mod tri6;
pub use crate::shapes::enums::*;
pub use crate::shapes::hex20::*;
pub use crate::shapes::hex8::*;
pub use crate::shapes::lin2::*;
pub use crate::shapes::lin3::*;
pub use crate::shapes::lin4::*;
pub use crate::shapes::lin5::*;
pub use crate::shapes::qua12::*;
pub use crate::shapes::qua16::*;
pub use crate::shapes::qua17::*;
pub use crate::shapes::qua4::*;
pub use crate::shapes::qua8::*;
pub use crate::shapes::qua9::*;
pub use crate::shapes::shape::*;
pub use crate::shapes::state_of_shape::*;
pub use crate::shapes::tet10::*;
pub use crate::shapes::tet4::*;
pub use crate::shapes::tri10::*;
pub use crate::shapes::tri15::*;
pub use crate::shapes::tri3::*;
pub use crate::shapes::tri6::*;
<|endoftext|>


<commit_before>use std::env;
use std::io::Read;
use std::fs::File;
use std::path::PathBuf;
use std::collections::HashMap;

fn main() {
    let mut data_path: std::path::PathBuf = env::current_dir().unwrap();
    data_path.push("data");
    data_path.push("input.txt");

    let directions: Vec<String> = data_from_file(&data_path).unwrap();

    let longest_distance: i32 = longest_block_distance(&directions);

    println!("Answer 1: {}", longest_distance);
}

pub fn data_from_file(file_name: &PathBuf) ->
        Result<Vec<String>, std::io::Error> {
    let mut data_file: File = File::open(file_name)?;
    let mut data_line: String = String::new();

    data_file.read_to_string(&mut data_line)?;

    let data: Vec<String> = data_line.trim()
                                     .split(", ")
                                     .map(|str_literal| str_literal.to_owned())
                                     .collect();

    Ok(data)
}

pub fn longest_block_distance(directions: &Vec<String>) -> i32 {
    let mut index: i32 = 0;
    let mut ew_parity: i32 = 1;
    let mut ns_parity: i32 = 1;

    let mut direction_parity_table: HashMap<char, i32> = HashMap::new();
    direction_parity_table.insert('R', 1);
    direction_parity_table.insert('L', -1);

    let mut travel_location: [i32; 2] = [0, 0];

    for direction in directions {
        let direction_parity: &i32 = direction_parity_table.get(
            &(direction.chars().nth(0).unwrap())).unwrap();
        let distance: i32 = (&direction[1..]).parse().unwrap();

        if index % 2 == 0 {
            if ns_parity == 1 {
                ew_parity = *direction_parity;
            } else {
                ew_parity = -1 * (*direction_parity);
            }

            travel_location[1] += ew_parity * distance;
        } else {
            if ew_parity == 1 {
                ns_parity = -1 * (*direction_parity);
            } else {
                ns_parity = *direction_parity;
            }

            travel_location[0] += ns_parity * distance;
       }

        index += 1;
    }

    return travel_location.iter().sum();
}

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

    #[test]
    fn test_longest_distance() {
        assert_eq!(longest_block_distance(&vec!["R2", "L3"]), 5);
    }
}<commit_msg>Finished day 1 in Rust!!!!<commit_after>use std::env;
use std::io::Read;
use std::fs::File;
use std::path::PathBuf;
use std::collections::HashMap;
use std::collections::HashSet;

fn main() {
    let mut data_path: PathBuf = env::current_dir().unwrap();
    data_path.push("data");
    data_path.push("input.txt");

    let directions: Vec<String> = data_from_file(&data_path).unwrap();

    let longest_distance: i32 = longest_block_distance(&directions);

    let distance_to_reoccurance: i32 =
        first_reoccuring_block_distance(&directions);

    println!("Answer 1: {}", longest_distance);
    println!("Answer 2: {}", distance_to_reoccurance);
}

pub fn data_from_file(file_name: &PathBuf) ->
        Result<Vec<String>, std::io::Error> {
    let mut data_file: File = File::open(file_name)?;
    let mut data_line: String = String::new();

    data_file.read_to_string(&mut data_line)?;

    let data: Vec<String> = data_line.trim()
                                     .split(", ")
                                     .map(|str_literal| str_literal.to_owned())
                                     .collect();

    Ok(data)
}

pub fn longest_block_distance(directions: &Vec<String>) -> i32 {
    let mut index: i32 = 0;
    let mut ew_parity: i32 = 1;
    let mut ns_parity: i32 = 1;

    let mut direction_parity_table: HashMap<char, i32> = HashMap::new();
    direction_parity_table.insert('R', 1);
    direction_parity_table.insert('L', -1);

    let mut travel_location: [i32; 2] = [0, 0];

    for direction in directions {
        let direction_parity: &i32 = direction_parity_table.get(
            &(direction.chars().nth(0).unwrap())).unwrap();
        let distance: i32 = (&direction[1..]).parse().unwrap();

        if index % 2 == 0 {
            if ns_parity == 1 {
                ew_parity = *direction_parity;
            } else {
                ew_parity = -1 * (*direction_parity);
            }

            travel_location[1] += ew_parity * distance;
        } else {
            if ew_parity == 1 {
                ns_parity = -1 * (*direction_parity);
            } else {
                ns_parity = *direction_parity;
            }

            travel_location[0] += ns_parity * distance;
       }

        index += 1;
    }

    travel_location[0].abs() + travel_location[1].abs()
}

pub fn first_reoccuring_block_distance(directions: &Vec<String>) -> i32 {
    let mut index: i32 = 0;
    let mut ew_parity: i32 = 1;
    let mut ns_parity: i32 = 1;

    let mut direction_parity_table: HashMap<char, i32> = HashMap::new();
    direction_parity_table.insert('R', 1);
    direction_parity_table.insert('L', -1);

    let mut travel_location: [i32; 2] = [0, 0];

    let mut locations_visited: HashSet<[i32; 2]> = HashSet::new();
    locations_visited.insert(travel_location);

    for direction in directions {
        let direction_parity: &i32 = direction_parity_table.get(
            &(direction.chars().nth(0).unwrap())).unwrap();
        let distance: i32 = (&direction[1..]).parse().unwrap();

        if index % 2 == 0 {
            if ns_parity == 1 {
                ew_parity = *direction_parity;
            } else {
                ew_parity = -1 * (*direction_parity);
            }

            let mut travel_from: i32 = travel_location[1];

            travel_location[1] += ew_parity * distance;

            let travel_to: i32 = travel_location[1];

            while travel_from != travel_to {
                travel_from += ew_parity;

                let temp_location: [i32; 2] =
                    [travel_location[0], travel_from];

                if locations_visited.contains(&temp_location) {
                    return temp_location[0].abs() + temp_location[1].abs();
                }

                locations_visited.insert(temp_location);
            }
        } else {
            if ew_parity == 1 {
                ns_parity = -1 * (*direction_parity);
            } else {
                ns_parity = *direction_parity;
            }

            let mut travel_from: i32 = travel_location[0];

            travel_location[0] += ns_parity * distance;

            let travel_to: i32 = travel_location[0];

            while travel_from != travel_to {
                travel_from += ns_parity;

                let temp_location: [i32; 2] =
                    [travel_from, travel_location[1]];

                if locations_visited.contains(&temp_location) {
                    return temp_location[0].abs() + temp_location[1].abs();
                }

                locations_visited.insert(temp_location);
            }
       }

        index += 1;
    }

    return -1;
}

// Testing
#[cfg(test)]
mod tests {
    use super::*;
    use std::env;
    use std::path::PathBuf;

    #[test]
    fn test_data_from_file() {
        let data_string: String = (
            "R1, R3, L2, L5, L2, L1, R3, L4, R2, L2, L4, R2, L1, R1, L2, R3, \
            L1, L4, R2, L5, R3, R4, L1, R2, L1, R3, L4, R5, L4, L5, R5, L3, \
            R2, L3, L3, R1, R3, L4, R2, R5, L4, R1, L1, L1, R5, L2, R1, L2, \
            R188, L5, L3, R5, R1, L2, L4, R3, R5, L3, R3, R45, L4, R4, R72, \
            R2, R3, L1, R1, L1, L1, R192, L1, L1, L1, L4, R1, L2, L5, L3, R5, \
            L3, R3, L4, L3, R1, R4, L2, R2, R3, L5, R3, L1, R1, R4, L2, L3, \
            R1, R3, L4, L3, L4, L2, L2, R1, R3, L5, L1, R4, R2, L4, L1, R3, \
            R3, R1, L5, L2, R4, R4, R2, R1, R5, R5, L4, L1, R5, R3, R4, R5, \
            R3, L1, L2, L4, R1, R4, R5, L2, L3, R4, L4, R2, L2, L4, L2, R5, \
            R1, R4, R3, R5, L4, L4, L5, L5, R3, R4, L1, L3, R2, L2, R1, L3, \
            L5, R5, R5, R3, L4, L2, R4, R5, R1, R4, L3").to_owned();

        let data_vec: Vec<String> = data_string.split(", ")
                                               .map(|s| s.to_owned())
                                               .collect();

        let mut data_path: PathBuf = env::current_dir().unwrap();
        data_path.push("data");
        data_path.push("input.txt");

        assert_eq!(data_from_file(&data_path).unwrap(), data_vec);
    }

    #[test]
    fn test_longest_distance() {
        assert_eq!(
            longest_block_distance(
                &(vec!["R2".to_owned(), "L3".to_owned()])), 5);

        assert_eq!(
            longest_block_distance(
                &(vec!["R2".to_owned(), "R2".to_owned(), "R2".to_owned()])), 2);

        assert_eq!(
            longest_block_distance(
                &(vec![
                    "R5".to_owned(), "L5".to_owned(), "R5".to_owned(),
                    "R3".to_owned()])),
            12);
    }

    #[test]
    fn test_first_reoccuring_block_distance() {
        let test_vec: Vec<String> =
            vec!["R8".to_owned(), "R4".to_owned(), "R4".to_owned(),
                 "R8".to_owned()];

        assert_eq!(first_reoccuring_block_distance(&test_vec), 4);
    }
}<|endoftext|>


<commit_before>use specs::{ReadStorage, System, WriteStorage};

use crate::combat::components::{Controller, Direction, Velocity, WalkingState};

pub const X_STEP_SIZES: [[i32; 4]; 3] = [[25, 3, 23, 4], [0, 0, 0, 0], [25, 3, 23, 4]];
pub const Y_STEP_SIZES: [[i32; 4]; 3] = [[8, 2, 9, 2], [0, 0, 0, 0], [2, 9, 2, 9]];
// check y step sizes

pub struct VelocitySystem;

impl<'a> System<'a> for VelocitySystem {
    type SystemData = (
        ReadStorage<'a, Controller>,
        WriteStorage<'a, Velocity>,
        WriteStorage<'a, WalkingState>,
    );

    fn run(&mut self, (controller, mut velocity, mut walking_state): Self::SystemData) {
        use specs::Join;

        for (controller, velocity, walking_state) in
            (&controller, &mut velocity, &mut walking_state).join()
        {
            let is_moving = (controller.x | controller.y) & 1;
            let step = ((walking_state.step + 1) % 4) * is_moving as u32;

            velocity.x = X_STEP_SIZES[(controller.x + 1) as usize][step as usize] * controller.x;
            velocity.y = Y_STEP_SIZES[(controller.y + 1) as usize][step as usize] * controller.y;

            if is_moving != 0 {
                walking_state.step = step;
            }
            match controller.x {
                1 => walking_state.direction = Direction::Right,
                -1 => walking_state.direction = Direction::Left,
                _ => (),
            }
            println!("{:?}", walking_state);
        }
    }
}
<commit_msg>Rust: only update step if moving<commit_after>use specs::{ReadStorage, System, WriteStorage};

use crate::combat::components::{Controller, Direction, Velocity, WalkingState};

pub const X_STEP_SIZES: [[i32; 4]; 3] = [[25, 3, 23, 4], [0, 0, 0, 0], [25, 3, 23, 4]];
pub const Y_STEP_SIZES: [[i32; 4]; 3] = [[8, 2, 9, 2], [0, 0, 0, 0], [2, 9, 2, 9]];
// check y step sizes

pub struct VelocitySystem;

impl<'a> System<'a> for VelocitySystem {
    type SystemData = (
        ReadStorage<'a, Controller>,
        WriteStorage<'a, Velocity>,
        WriteStorage<'a, WalkingState>,
    );

    fn run(&mut self, (controller, mut velocity, mut walking_state): Self::SystemData) {
        use specs::Join;

        for (controller, velocity, walking_state) in
            (&controller, &mut velocity, &mut walking_state).join()
        {
            let is_moving = (controller.x | controller.y) & 1;
            if is_moving != 0 {
                let step = ((walking_state.step + 1) % 4) * is_moving as u32;

                velocity.x =
                    X_STEP_SIZES[(controller.x + 1) as usize][step as usize] * controller.x;
                velocity.y =
                    Y_STEP_SIZES[(controller.y + 1) as usize][step as usize] * controller.y;
                walking_state.step = step;
            } else {
                velocity.x = 0;
                velocity.y = 0;
            }
            match controller.x {
                1 => walking_state.direction = Direction::Right,
                -1 => walking_state.direction = Direction::Left,
                _ => (),
            }
        }
    }
}
<|endoftext|>


<commit_before>#![doc(include = "README.md")]

extern crate base64;
extern crate base64_serde;
extern crate serde;

use base64::STANDARD;
use base64_serde::base64_serde_type;
use serde::{Deserialize, Serialize};

base64_serde_type!(Base64Standard, STANDARD);

/// Wraps a language tag string, as defined in
/// https://tools.ietf.org/html/bcp47
#[derive(Serialize, Deserialize, Clone)]
pub struct LanguageTag(pub String);

/// Wraps a media type string, as defined in
/// https://tools.ietf.org/html/rfc7231#section-3.1.1.1
#[derive(Serialize, Deserialize, Clone)]
pub struct MediaType(pub String);

/// Wraps a sanitized file name.
/// Allows extensions, but no path components.
#[derive(Serialize, Deserialize, Clone)]
pub struct FileName(pub String);

/// A variant of a text (say, for a given locale).
#[derive(Serialize, Deserialize, Clone)]
pub struct TextVariant {
    #[serde(default)]
    pub attributes: Vec<VariantAttribute>,

    pub value: String,
}

/// An attribute of a variant, used for content negotiation
#[derive(Serialize, Deserialize, Clone)]
pub struct VariantAttribute {
    pub key: String,
    pub value: String,
}

/// A text to show to users, expressed as a collection of variants (for content negotiation).
pub type Text = Vec<TextVariant>;

/// A variant of a file (say, for a given locale).
#[derive(Serialize, Deserialize, Clone)]
pub struct FileVariant {
    #[serde(default)]
    pub attributes: Vec<VariantAttribute>,

    pub name: Option<FileName>,
    pub r#type: Option<MediaType>,

    #[serde(with = "Base64Standard")]
    pub content: Vec<u8>,
}

/// A file, expressed as a collection of variants (for content negotiation).
pub type File = Vec<FileVariant>;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
<commit_msg>content: improve documentation<commit_after>#![doc(include = "README.md")]

extern crate base64;
extern crate base64_serde;
extern crate serde;

use base64::STANDARD;
use base64_serde::base64_serde_type;
use serde::{Deserialize, Serialize};

base64_serde_type!(Base64Standard, STANDARD);

/// Wraps a language tag string, as defined in
/// https://tools.ietf.org/html/bcp47
#[derive(Serialize, Deserialize, Clone)]
pub struct LanguageTag(pub String);

/// Wraps a media type string, as defined in
/// https://tools.ietf.org/html/rfc7231#section-3.1.1.1
#[derive(Serialize, Deserialize, Clone)]
pub struct MediaType(pub String);

/// Wraps a sanitized file name.
/// Allows extensions, but no path components.
#[derive(Serialize, Deserialize, Clone)]
pub struct FileName(pub String);

/// A variant of a text (say, for a given locale).
#[derive(Serialize, Deserialize, Clone)]
pub struct TextVariant {
    /// Attributes of this variant, used for content negotiation
    #[serde(default)]
    pub attributes: Vec<VariantAttribute>,

    /// Actual text of this variant
    pub value: String,
}

/// An attribute of a variant, used for content negotiation
#[derive(Serialize, Deserialize, Clone)]
pub struct VariantAttribute {
    pub key: String,
    pub value: String,
}

/// A text to show to users, expressed as a collection of variants (for content negotiation).
pub type Text = Vec<TextVariant>;

/// A variant of a file (say, for a given locale).
#[derive(Serialize, Deserialize, Clone)]
pub struct FileVariant {
    /// Attributes of this variant, used for content negotiation
    #[serde(default)]
    pub attributes: Vec<VariantAttribute>,

    /// Name of this file, if relevant
    pub name: Option<FileName>,
    /// Media type of this file, if relevant
    pub r#type: Option<MediaType>,

    /// Byte content of this file
    #[serde(with = "Base64Standard")]
    pub content: Vec<u8>,
}

/// A file, expressed as a collection of variants (for content negotiation).
pub type File = Vec<FileVariant>;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]

#![plugin(clippy)]

#![deny(clippy)]
#![deny(clippy_pedantic)]
#![allow(print_stdout)]
#![allow(clone_on_copy)]
#![allow(many_single_char_names)]

#![allow(use_debug)]

#[derive(Debug)]
struct Moo{
    a:i32, //I guess no one else can access these fields(unless marked pub) except me from within here
    b:i32,
    c:String
}

fn main() {
    let mut a = [1, 2, 3, 4, 5];

    //implicit copying OR moving - the bane of Rust :)
    let first = a[0]; //can I prevent this Copy from happening? a lint for it? eg. I actually wanted &a[0] or a move
    let oldfirst = a[0].clone();//this is acceptable! but implicitly copy like above isn't! TODO: find a way to disable Copy trait!

    a[0] = 7;
    let reffirst:&i32 = &a[0]; //TODO: find out how to keep a ref and still allow assignment - eg. move this line above the assignment line a[0]=7; and have it work!

    println!("The value of first is: {} {} {}", first, oldfirst, reffirst);

    //same syntax can do either an implicity copy or an implicit move - i'd rather have one or the
    //other! if not at least warn me?
    let a1 = [1,2,3];
    let first1 = a[0]; // implicit copy
    let second = a[1];
    let b = [String::from("1"),String::from("2"),String::from("3")];
//    let fb=b[0]; // this wants to do an implicit move
//    let sb=b[1];

    let meh = String::from("meh");
    let mut x=Moo{a:1,b:2,c:meh};
//    println!("{}",meh);//meh was moved! awesome! i approve
//    let y=x;//moved!
    let y=x.a;//copy!
    x.a=3;//bye bye stale value y, right now.
    println!("{:?} {}",x,y);

    let z=&x.a;//borrowed! eg.temp moved!
//    x.a=4;//can't do this! this is great!
//    TODO: how do I do explicit move tho?
    println!("{:?} {}",x,y);
    {
        let mut q=x.c;//implicitly moved.
    //    println!("{:?}",x);//can't do this: use of partially moved value!
        q.push_str("something");
    //    but can still access the other fields meanwhile. hmm...
        let somethingelse=x.a;//hmm, maybe this isn't as bad as I thought...or is it? I'm unsure... will get back to this after I know more!
        x.c=q;//move it back!
//        x.c=String::from("meh2");//or, assign new stuff instead - so it's not partially moved
//        value anymore!
    }//block has no effect, I just have to move it back manually! obv.
    println!("{:?}",x);
}
<commit_msg>why clippy is my god<commit_after>#![feature(plugin)]

#![plugin(clippy)]

#![deny(clippy)]
#![deny(clippy_pedantic)]
#![allow(print_stdout)]
#![allow(clone_on_copy)]
#![allow(many_single_char_names)]

#![allow(use_debug)]

#[derive(Debug)]
struct Moo{
    a:i32, //I guess no one else can access these fields(unless marked pub) except me from within here
    b:i32,
    c:String
}

fn main() {
    let mut a = [1, 2, 3, 4, 5];

    //implicit copying OR moving - the bane of Rust :)
    let first = a[0]; //can I prevent this Copy from happening? a lint for it? eg. I actually wanted &a[0] or a move
    let oldfirst = a[0].clone();//this is acceptable! but implicitly copy like above isn't! TODO: find a way to disable Copy trait!

    a[0] = 7;
    let reffirst:&i32 = &a[0]; //TODO: find out how to keep a ref and still allow assignment - eg. move this line above the assignment line a[0]=7; and have it work!

    println!("The value of first is: {} {} {}", first, oldfirst, reffirst);

    //same syntax can do either an implicity copy or an implicit move - i'd rather have one or the
    //other! if not at least warn me?
    let a1 = [1,2,3];
    let first1 = a[0]; // implicit copy
    let second = a[1];
    let b = [String::from("1"),String::from("2"),String::from("3")];
//    let fb=b[0]; // this wants to do an implicit move
//    let sb=b[1];

    let meh = String::from("meh");
    let mut x=Moo{a:1,b:2,c:meh};
//    println!("{}",meh);//meh was moved! awesome! i approve
//    let y=x;//moved!
    let y=x.a;//copy!
    x.a=3;//bye bye stale value y, right now.
    println!("{:?} {}",x,y);

    let z=&x.a;//borrowed! eg.temp moved!
//    x.a=4;//can't do this! this is great!
//    TODO: how do I do explicit move tho?
    println!("{:?} {}",x,y);
    {
        let mut q=x.c;//implicitly moved.
    //    println!("{:?}",x);//can't do this: use of partially moved value!
        q.push_str("something");
    //    but can still access the other fields meanwhile. hmm...
        let somethingelse=x.a;//hmm, maybe this isn't as bad as I thought...or is it? I'm unsure... will get back to this after I know more!
        x.c=q;//move it back!
//        x.c=String::from("meh2");//or, assign new stuff instead - so it's not partially moved
//        value anymore!
    }//block has no effect, I just have to move it back manually! obv.
    println!("{:?}",x);

//    let a=1;
//    let a=2;//not allowed by clippy - this is why I love it! hehe
}
<|endoftext|>


<commit_before>use crate::client_died_error_holder::DiedType;
use crate::client_died_error_holder::SomethingDiedErrorHolder;
use futures::channel::mpsc;
use futures::channel::mpsc::UnboundedReceiver;
use futures::channel::mpsc::UnboundedSender;
use futures::stream::Stream;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;

pub(crate) trait ErrorAwareDrop {
    type DiedType: DiedType;

    fn drop_with_error(self, error: crate::Error);
}

pub(crate) struct DeathAwareSender<T: ErrorAwareDrop> {
    tx: UnboundedSender<T>,
    conn_died_error_holder: SomethingDiedErrorHolder<T::DiedType>,
}

pub(crate) struct DeathAwareReceiver<T: ErrorAwareDrop> {
    rx: UnboundedReceiver<T>,
    conn_died_error_holder: SomethingDiedErrorHolder<T::DiedType>,
}

impl<T: ErrorAwareDrop> Drop for DeathAwareReceiver<T> {
    fn drop(&mut self) {
        while let Ok(Some(m)) = self.rx.try_next() {
            m.drop_with_error(self.conn_died_error_holder.error());
        }
    }
}

impl<T: ErrorAwareDrop> Clone for DeathAwareSender<T> {
    fn clone(&self) -> Self {
        DeathAwareSender {
            tx: self.tx.clone(),
            conn_died_error_holder: self.conn_died_error_holder.clone(),
        }
    }
}

impl<T: ErrorAwareDrop> DeathAwareSender<T> {
    pub fn unbounded_send_recover(&self, msg: T) -> Result<(), (T, crate::Error)> {
        self.tx
            .unbounded_send(msg)
            .map_err(|e| (e.into_inner(), self.conn_died_error_holder.error()))
    }

    pub fn unbounded_send(&self, msg: T) -> crate::Result<()> {
        self.unbounded_send_recover(msg).map_err(|(_, e)| e)
    }
}

impl<T: ErrorAwareDrop> Stream for DeathAwareReceiver<T> {
    type Item = T;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
        Pin::new(&mut self.rx).poll_next(cx)
    }
}

pub(crate) fn death_aware_channel<T: ErrorAwareDrop>(
    conn_died_error_holder: SomethingDiedErrorHolder<T::DiedType>,
) -> (DeathAwareSender<T>, DeathAwareReceiver<T>) {
    let (tx, rx) = mpsc::unbounded();
    let tx = DeathAwareSender {
        tx,
        conn_died_error_holder: conn_died_error_holder.clone(),
    };
    let rx = DeathAwareReceiver {
        rx,
        conn_died_error_holder,
    };
    (tx, rx)
}
<commit_msg>Explicitly close channel in DeathAwareReceiver<commit_after>use crate::client_died_error_holder::DiedType;
use crate::client_died_error_holder::SomethingDiedErrorHolder;
use futures::channel::mpsc;
use futures::channel::mpsc::UnboundedReceiver;
use futures::channel::mpsc::UnboundedSender;
use futures::stream::Stream;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;

pub(crate) trait ErrorAwareDrop {
    type DiedType: DiedType;

    fn drop_with_error(self, error: crate::Error);
}

pub(crate) struct DeathAwareSender<T: ErrorAwareDrop> {
    tx: UnboundedSender<T>,
    conn_died_error_holder: SomethingDiedErrorHolder<T::DiedType>,
}

pub(crate) struct DeathAwareReceiver<T: ErrorAwareDrop> {
    rx: UnboundedReceiver<T>,
    conn_died_error_holder: SomethingDiedErrorHolder<T::DiedType>,
}

impl<T: ErrorAwareDrop> Drop for DeathAwareReceiver<T> {
    fn drop(&mut self) {
        self.rx.close();

        while let Ok(Some(m)) = self.rx.try_next() {
            m.drop_with_error(self.conn_died_error_holder.error());
        }
    }
}

impl<T: ErrorAwareDrop> Clone for DeathAwareSender<T> {
    fn clone(&self) -> Self {
        DeathAwareSender {
            tx: self.tx.clone(),
            conn_died_error_holder: self.conn_died_error_holder.clone(),
        }
    }
}

impl<T: ErrorAwareDrop> DeathAwareSender<T> {
    pub fn unbounded_send_recover(&self, msg: T) -> Result<(), (T, crate::Error)> {
        self.tx
            .unbounded_send(msg)
            .map_err(|e| (e.into_inner(), self.conn_died_error_holder.error()))
    }

    pub fn unbounded_send(&self, msg: T) -> crate::Result<()> {
        self.unbounded_send_recover(msg).map_err(|(_, e)| e)
    }
}

impl<T: ErrorAwareDrop> Stream for DeathAwareReceiver<T> {
    type Item = T;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
        Pin::new(&mut self.rx).poll_next(cx)
    }
}

pub(crate) fn death_aware_channel<T: ErrorAwareDrop>(
    conn_died_error_holder: SomethingDiedErrorHolder<T::DiedType>,
) -> (DeathAwareSender<T>, DeathAwareReceiver<T>) {
    let (tx, rx) = mpsc::unbounded();
    let tx = DeathAwareSender {
        tx,
        conn_died_error_holder: conn_died_error_holder.clone(),
    };
    let rx = DeathAwareReceiver {
        rx,
        conn_died_error_holder,
    };
    (tx, rx)
}
<|endoftext|>


<commit_before><commit_msg>Fix deprecated anonymous functions parameters<commit_after><|endoftext|>


<commit_before>// extern crate bindgen;
#[cfg(target_env = "msvc")]
extern crate cc;
extern crate pkg_config;
extern crate num_cpus;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

// Automatically write bindings to libsass
//#[allow(dead_code)]
//fn write_bindings() {
//    let bindings = bindgen::Builder::default()
//        .header("libsass/include/sass.h")
//        .clang_arg("-Ilibsass/include")
//        // To avoid a test failing
//        .blacklist_type("max_align_t")
//        // we do static linking so it should be fine
//        // https://github.com/rust-lang/rust/issues/36927
//        .rustified_enum(".*")
//        .generate()
//        .expect("Unable to generate bindings");
//
//    // Write the bindings to the $OUT_DIR/bindings.rs file.
//    let out_path = PathBuf::from("src");
//    bindings
//        .write_to_file(out_path.join("bindings.rs"))
//        .expect("Couldn't write bindings!");
//}

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => panic!("\n{} failed with {}\n", stringify!($e), e),
    })
}

fn cp_r(dir: &Path, dest: &Path) {
    for entry in t!(fs::read_dir(dir)) {
        let entry = t!(entry);
        let path = entry.path();
        let dst = dest.join(path.file_name().expect("Failed to get filename of path"));
        if t!(fs::metadata(&path)).is_file() {
            t!(fs::copy(path, dst));
        } else {
            t!(fs::create_dir_all(&dst));
            cp_r(&path, &dst);
        }
    }
}

// CIs usually do it automatically but for normal users libsass would be missing
fn init_submodule() {
    Command::new("git")
        .arg("submodule")
        .arg("init")
        .stderr(Stdio::null())
        .status()
        .expect("Failed to run 'git submodule init'. Do you have git installed?")
        .success();
    Command::new("git")
        .arg("submodule")
        .arg("update")
        .stderr(Stdio::null())
        .status()
        .expect("Failed to run 'git submodule update'. Do you have git installed?")
        .success();
}

fn get_libsass_folder() -> PathBuf {
    env::current_dir().expect("Failed to get the current directory").join("libsass")
}

#[cfg(target_os = "linux")]
fn _compile(libprobe: fn(&str) -> bool) {
    if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    } else if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    } else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    } else {
        panic!("no c++ library found");
    }
}

#[cfg(not(target_os = "linux"))]
fn _compile(libprobe: fn(&str) -> bool) {
    if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    } else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    } else if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    } else {
        panic!("no c++ library found");
    }
}

// linux/unix
#[cfg(not(target_env = "msvc"))]
fn compile() {
    let target = env::var("TARGET").expect("TARGET not found");
    let src = get_libsass_folder();
    let dest = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR not found"));
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);
    let is_bsd = target.contains("dragonfly")
        || target.contains("freebsd")
        || target.contains("netbsd")
        || target.contains("openbsd");
    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or_else(|_| num_cpus::get().to_string());
    let r = Command::new(if is_bsd { "gmake" } else { "make" })
        .current_dir(&build)
        .args(&["--jobs", &jobs])
        .output()
        .expect("Failed to run make/gmake. Do you have it installed?");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("lib").display()
    );
    println!("cargo:rustc-link-lib=static=sass");

    let libprobe = | lib: &str | -> bool {
      Command::new("cc")
        .arg("-xc++")
        .arg("-o/dev/null")
        .arg(format!("-l{}",lib))
        .arg("-shared")
        .stderr(Stdio::null())
        .status()
        .expect("Failed to run cc. Do you have it installed?")
        .success()
    };
    _compile(libprobe);
}

// windows
#[cfg(target_env = "msvc")]
fn compile() {
    let src = get_libsass_folder();
    let target = env::var("TARGET").expect("TARGET not found in environment");
    let msvc_platform = if target.contains("x86_64") {
        "Win64"
    } else {
        "Win32"
    };
    let dest = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR not found in environment"));
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);

    // Find an instance of devenv.exe from Visual Studio IDE in order to upgrade
    // libsass.sln to the current available IDE. Do nothing if no devenv.exe found
    let d = cc::windows_registry::find(target.as_str(), "devenv.exe");
    if let Some(mut d) = d {
        let d = d
            .args(&["/upgrade", "win\\libsass.sln"])
            .current_dir(&build)
            .output()
            .expect("Failed to run devenv. Do you have it installed?");
        if !d.status.success() {
            let err = String::from_utf8_lossy(&d.stderr);
            let out = String::from_utf8_lossy(&d.stdout);
            println!("Upgrade error:\nSTDERR:{}\nSTDOUT:{}", err, out);
        }
    }

    let search = Command::new("where")
        .args(&["msbuild.exe"])
        .output()
        .expect("Failed to run where: Could not search for msbuild.exe on path.");
    let mut msbuild = if search.status.success() {
        Command::new("msbuild.exe")
    } else {
        cc::windows_registry::find(target.as_str(), "msbuild.exe")
            .expect("Could not find msbuild.exe on the registry")
    };

    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or_else(|_| num_cpus::get().to_string());

    let r = msbuild
        .args(&[
            "win\\libsass.sln",
            "/p:LIBSASS_STATIC_LIB=1",
            "/p:Configuration=Release",
            "/p:WholeProgramOptimization=false",
            format!("/m:{}", jobs).as_str(),
            format!("/p:Platform={}", msvc_platform).as_str(),
        ])
        .current_dir(&build)
        .output()
        .expect("Failed to run msbuild. Do you have it installed?");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("win").join("bin").display()
    );
    println!("cargo:rustc-link-lib=static=libsass");
}

fn main() {
    // Uncomment the line below to generate bindings. Doesn't work on CI as it
    // requires additional tooling
    // write_bindings();

    // Is it already built?
    if let Ok(_) = pkg_config::find_library("libsass") {
        return;
    }

    init_submodule();
    compile();
}
<commit_msg>Remove submodule init from build.rs<commit_after>// extern crate bindgen;
#[cfg(target_env = "msvc")]
extern crate cc;
extern crate pkg_config;
extern crate num_cpus;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

// Automatically write bindings to libsass
//#[allow(dead_code)]
//fn write_bindings() {
//    let bindings = bindgen::Builder::default()
//        .header("libsass/include/sass.h")
//        .clang_arg("-Ilibsass/include")
//        // To avoid a test failing
//        .blacklist_type("max_align_t")
//        // we do static linking so it should be fine
//        // https://github.com/rust-lang/rust/issues/36927
//        .rustified_enum(".*")
//        .generate()
//        .expect("Unable to generate bindings");
//
//    // Write the bindings to the $OUT_DIR/bindings.rs file.
//    let out_path = PathBuf::from("src");
//    bindings
//        .write_to_file(out_path.join("bindings.rs"))
//        .expect("Couldn't write bindings!");
//}

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => panic!("\n{} failed with {}\n", stringify!($e), e),
    })
}

fn cp_r(dir: &Path, dest: &Path) {
    for entry in t!(fs::read_dir(dir)) {
        let entry = t!(entry);
        let path = entry.path();
        let dst = dest.join(path.file_name().expect("Failed to get filename of path"));
        if t!(fs::metadata(&path)).is_file() {
            t!(fs::copy(path, dst));
        } else {
            t!(fs::create_dir_all(&dst));
            cp_r(&path, &dst);
        }
    }
}

fn get_libsass_folder() -> PathBuf {
    env::current_dir().expect("Failed to get the current directory").join("libsass")
}

#[cfg(target_os = "linux")]
fn _compile(libprobe: fn(&str) -> bool) {
    if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    } else if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    } else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    } else {
        panic!("no c++ library found");
    }
}

#[cfg(not(target_os = "linux"))]
fn _compile(libprobe: fn(&str) -> bool) {
    if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    } else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    } else if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    } else {
        panic!("no c++ library found");
    }
}

// linux/unix
#[cfg(not(target_env = "msvc"))]
fn compile() {
    let target = env::var("TARGET").expect("TARGET not found");
    let src = get_libsass_folder();
    let dest = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR not found"));
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);
    let is_bsd = target.contains("dragonfly")
        || target.contains("freebsd")
        || target.contains("netbsd")
        || target.contains("openbsd");
    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or_else(|_| num_cpus::get().to_string());
    let r = Command::new(if is_bsd { "gmake" } else { "make" })
        .current_dir(&build)
        .args(&["--jobs", &jobs])
        .output()
        .expect("Failed to run make/gmake. Do you have it installed?");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("lib").display()
    );
    println!("cargo:rustc-link-lib=static=sass");

    let libprobe = | lib: &str | -> bool {
      Command::new("cc")
        .arg("-xc++")
        .arg("-o/dev/null")
        .arg(format!("-l{}",lib))
        .arg("-shared")
        .stderr(Stdio::null())
        .status()
        .expect("Failed to run cc. Do you have it installed?")
        .success()
    };
    _compile(libprobe);
}

// windows
#[cfg(target_env = "msvc")]
fn compile() {
    let src = get_libsass_folder();
    let target = env::var("TARGET").expect("TARGET not found in environment");
    let msvc_platform = if target.contains("x86_64") {
        "Win64"
    } else {
        "Win32"
    };
    let dest = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR not found in environment"));
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);

    // Find an instance of devenv.exe from Visual Studio IDE in order to upgrade
    // libsass.sln to the current available IDE. Do nothing if no devenv.exe found
    let d = cc::windows_registry::find(target.as_str(), "devenv.exe");
    if let Some(mut d) = d {
        let d = d
            .args(&["/upgrade", "win\\libsass.sln"])
            .current_dir(&build)
            .output()
            .expect("Failed to run devenv. Do you have it installed?");
        if !d.status.success() {
            let err = String::from_utf8_lossy(&d.stderr);
            let out = String::from_utf8_lossy(&d.stdout);
            println!("Upgrade error:\nSTDERR:{}\nSTDOUT:{}", err, out);
        }
    }

    let search = Command::new("where")
        .args(&["msbuild.exe"])
        .output()
        .expect("Failed to run where: Could not search for msbuild.exe on path.");
    let mut msbuild = if search.status.success() {
        Command::new("msbuild.exe")
    } else {
        cc::windows_registry::find(target.as_str(), "msbuild.exe")
            .expect("Could not find msbuild.exe on the registry")
    };

    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or_else(|_| num_cpus::get().to_string());

    let r = msbuild
        .args(&[
            "win\\libsass.sln",
            "/p:LIBSASS_STATIC_LIB=1",
            "/p:Configuration=Release",
            "/p:WholeProgramOptimization=false",
            format!("/m:{}", jobs).as_str(),
            format!("/p:Platform={}", msvc_platform).as_str(),
        ])
        .current_dir(&build)
        .output()
        .expect("Failed to run msbuild. Do you have it installed?");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("win").join("bin").display()
    );
    println!("cargo:rustc-link-lib=static=libsass");
}

fn main() {
    // Uncomment the line below to generate bindings. Doesn't work on CI as it
    // requires additional tooling
    // write_bindings();

    // Is it already built?
    if let Ok(_) = pkg_config::find_library("libsass") {
        return;
    }

    compile();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use nom::{IResult,Needed,FlatMapOpt,line_ending,not_line_ending, space, alphanumeric, multispace};
use nom::IResult::*;

use std::str;
use std::collections::HashMap;<commit_msg>Start on main library module<commit_after>#![crate_name = "seax_scheme"]
#![crate_type = "lib"]
pub mod ast;
pub mod parser;<|endoftext|>


<commit_before>extern crate chrono;
extern crate clap;
extern crate csv;
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate safe_unwrap;
extern crate try_from;

use chrono::NaiveDate;
use clap::{App, Arg, SubCommand};
use std::{io, path};
use regex::Regex;
use safe_unwrap::SafeUnwrap;
use try_from::TryFrom;

lazy_static! {
    static ref IDENT_RE: Regex = Regex::new(
        r"^[a-z][a-z0-9]*$"
    ).safe_unwrap("built-in Regex is broken. Please file a bug");
}

lazy_static! {
    static ref IDENT_HYPHEN_RE: Regex = Regex::new(
        r"^[a-z][a-z0-9-]*$"
    ).safe_unwrap("built-in Regex is broken. Please file a bug");
}

lazy_static! {
    static ref IDENT_UNDERSCORE_RE: Regex = Regex::new(
        r"^[a-z][a-z0-9_]*$"
    ).safe_unwrap("built-in Regex is broken. Please file a bug");
}

lazy_static! {
    static ref ENUM_EXPR_RE: Regex = Regex::new(
        r"^ENUM.*\(((?:[A-Z][A-Z0-9]*,?)*)\)$"
    ).safe_unwrap("built-in Regex is broken. Please file a bug");
}

lazy_static! {
    static ref CONSTRAINT_RE: Regex = Regex::new(
        r"^(:?(?:NULLABLE|UNIQUE),?)*$"
    ).safe_unwrap("built-in Regex is broken. Please file a bug");
}

#[derive(Clone, Debug, Eq, PartialEq)]
struct CsvxMetadata {
    pub table_name: String,
    pub date: NaiveDate,
    pub schema: String,
    pub csvx_version: usize,
}

impl CsvxMetadata {
    fn is_schema(&self) -> bool {
        self.schema == "csvx-schema"
    }
}

#[derive(Debug)]
enum SchemaLoadError {
    Csv(csv::Error),
    MissingHeader,
    BadHeader,
    BadIdentifier(usize, String),
    BadType(usize, ColumnTypeError),
    BadConstraints(usize, ColumnConstraintsError),
}

#[derive(Clone, Debug)]
enum ColumnTypeError {
    UnknownType,
}

#[derive(Clone, Debug)]
enum ColumnType {
    String,
    Bool,
    Integer,
    Enum(Vec<String>),
    Decimal,
    Date,
    DateTime,
    Time,
}

#[derive(Clone, Debug)]
struct ColumnConstraints {
    nullable: bool,
    unique: bool,
}

impl Default for ColumnConstraints {
    fn default() -> ColumnConstraints {
        ColumnConstraints {
            nullable: false,
            unique: false,
        }
    }
}

#[derive(Clone, Debug)]
enum ColumnConstraintsError {
    MalformedConstraint,
    UnknownConstraint(String),
}

impl<S> TryFrom<S> for ColumnConstraints
    where S: AsRef<str>
{
    type Err = ColumnConstraintsError;

    fn try_from(s: S) -> Result<ColumnConstraints, Self::Err> {
        if !CONSTRAINT_RE.is_match(s.as_ref()) {
            return Err(ColumnConstraintsError::MalformedConstraint);
        }

        let mut ccs = ColumnConstraints::default();

        if s.as_ref() == "" {
            return Ok(ccs);
        }

        for fragment in s.as_ref().split(',') {
            match s.as_ref() {
                "NULLABLE" => {
                    ccs.nullable = true;
                }
                "UNIQUE" => {
                    ccs.unique = true;
                }
                _ => return Err(ColumnConstraintsError::UnknownConstraint(s.as_ref().to_string())),
            }

        }

        Ok(ccs)
    }
}

impl<S> TryFrom<S> for ColumnType
    where S: AsRef<str>
{
    type Err = ColumnTypeError;

    fn try_from(s: S) -> Result<ColumnType, Self::Err> {
        match s.as_ref() {
            "STRING" => Ok(ColumnType::String),
            "BOOL" => Ok(ColumnType::Bool),
            "INTEGER" => Ok(ColumnType::Integer),
            "DECIMAL" => Ok(ColumnType::Decimal),
            "DATE" => Ok(ColumnType::Date),
            "DATETIME" => Ok(ColumnType::DateTime),
            "TIME" => Ok(ColumnType::Time),
            _ if ENUM_EXPR_RE.is_match(s.as_ref()) => {
                let variants: Vec<_> = ENUM_EXPR_RE
                    .captures(s.as_ref())
                    .safe_unwrap("match already exists")
                    .get(1)
                    .safe_unwrap("group 1 exists in regex")
                    .as_str()
                    .split(',')
                    .map(|s| s.to_owned())
                    .collect();

                Ok(ColumnType::Enum(variants))
            }
            _ => return Err(ColumnTypeError::UnknownType),

        }
    }
}

#[derive(Clone, Debug)]
struct CsvxColumnType {
    id: String,
    ty: ColumnType,
    constraints: ColumnConstraints,
    description: String,
}

#[derive(Clone, Debug)]
struct CsvxSchema {
    columns: Vec<CsvxColumnType>,
}

impl From<csv::Error> for SchemaLoadError {
    fn from(e: csv::Error) -> SchemaLoadError {
        SchemaLoadError::Csv(e)
    }
}

impl CsvxSchema {
    fn from_file<P: AsRef<path::Path>>(filename: P) -> Result<CsvxSchema, SchemaLoadError> {
        let mut rdr = csv::Reader::from_file(filename)?.has_headers(false);

        let mut it = rdr.decode();
        let header: Option<Result<(String, String, String, String), _>> = it.next();

        let mut columns = Vec::new();

        match header {
            None => return Err(SchemaLoadError::MissingHeader),
            Some(res) => {
                let fields = res?;

                println!("{:?}", fields);

                if fields.0 != "id" || fields.1 != "type" || fields.2 != "constraints" ||
                   fields.3 != "description" {

                    return Err(SchemaLoadError::BadHeader);
                }

                for (recno, rec) in it.enumerate() {
                    let (id, ty, constraints, desc) = rec?;
                    let lineno = recno + 2;

                    // check identifier
                    if !IDENT_UNDERSCORE_RE.is_match(&id.as_str()) {
                        return Err(SchemaLoadError::BadIdentifier(lineno, id));
                    }

                    // create type
                    let col_type = match ColumnType::try_from(ty.as_str()) {
                        Ok(v) => v,
                        Err(e) => return Err(SchemaLoadError::BadType(lineno, e)),
                    };

                    // create constraints
                    let col_constraints = match ColumnConstraints::try_from(constraints.as_str()) {
                        Ok(v) => v,
                        Err(e) => return Err(SchemaLoadError::BadConstraints(lineno, e)),
                    };

                    let col = CsvxColumnType {
                        id: id,
                        ty: col_type,
                        constraints: col_constraints,
                        description: desc,
                    };

                    columns.push(col)
                }

                Ok(CsvxSchema { columns: columns })
            }
        }

    }
}

#[inline]
fn cap<T>(c: &regex::Captures, idx: usize) -> T
    where T: std::str::FromStr,
          T::Err: std::fmt::Debug
{
    println!("TRYING: {:?}", c.get(idx));

    c.get(idx)
        .safe_unwrap("valid group")
        .as_str()
        .parse()
        .safe_unwrap("already validated through regex")

}

fn parse_filename<S: AsRef<str>>(filename: S) -> Option<CsvxMetadata> {
    lazy_static! {
        // `tablename_date_schema-schemaversion_csvxversion.csvx`
        static ref FN_RE: Regex = Regex::new(
            r"^([a-z][a-z0-9-]*)_(\d{4})(\d{2})(\d{2})_([a-z][a-z0-9-]*)_(\d+).csv$"
        ).expect("built-in Regex is broken. Please file a bug");
    }

    match FN_RE.captures(filename.as_ref()) {
        Some(caps) => {
            let table_name = caps.get(1)
                .safe_unwrap("known group")
                .as_str()
                .to_string();
            let year = cap(&caps, 2);
            let month = cap(&caps, 3);
            let day = cap(&caps, 4);
            let schema = caps.get(5)
                .safe_unwrap("known group")
                .as_str()
                .to_string();
            let csvx_version = cap(&caps, 6);

            Some(CsvxMetadata {
                     table_name: table_name,
                     date: NaiveDate::from_ymd(year, month, day),
                     schema: schema,
                     csvx_version: csvx_version,
                 })
        }
        None => None,
    }
}

fn main() {
    let app = App::new("csvx")
        .version("4.0.0")
        .about("csvx version 2 utility")
        .subcommand(SubCommand::with_name("check")
                        .about("Check csvx files for conformance")
                        .arg(Arg::with_name("schema_file")
                                 .help("Schema file to check against")
                                 .required(true)
                                 .takes_value(true))
                        .arg(Arg::with_name("input_files")
                                 .help("Input files to check")
                                 .multiple(true)
                                 .takes_value(true)));
    let m = app.clone().get_matches();

    match m.subcommand {
        Some(ref cmd) if cmd.name == "check" => {
            let schema_file = cmd.matches
                .value_of("schema_file")
                .safe_unwrap("required argument");

            let meta = parse_filename(schema_file).expect("filename is not in valid format");

            if !meta.is_schema() {
                println!("The supplied file {} is not a csvx schema (wrong filename)",
                         schema_file);
                return;
            }

            // load schema
            let schema = CsvxSchema::from_file(schema_file).unwrap();

            println!("{:?}", schema);
        }
        _ => app.write_help(&mut io::stdout()).unwrap(),
    }
}

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

    use chrono::NaiveDate;

    #[test]
    fn filename_parsing_rejects_invalid() {
        assert_eq!(parse_filename("asdf"), None);
        assert_eq!(parse_filename(""), None);
        assert_eq!(parse_filename("test.csv"), None);
        assert_eq!(parse_filename("test.csv"), None);
    }

    #[test]
    fn filename_parsing_parses_valid() {
        assert_eq!(parse_filename("zoo-nyc_20170401_animals-2_3.csv").unwrap(),
                   CsvxMetadata {
                       table_name: "zoo-nyc".to_owned(),
                       date: NaiveDate::from_ymd(2017, 04, 01),
                       schema: "animals-2".to_owned(),
                       csvx_version: 3,
                   });
    }

}
<commit_msg>Properly check fragment.<commit_after>extern crate chrono;
extern crate clap;
extern crate csv;
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate safe_unwrap;
extern crate try_from;

use chrono::NaiveDate;
use clap::{App, Arg, SubCommand};
use std::{io, path};
use regex::Regex;
use safe_unwrap::SafeUnwrap;
use try_from::TryFrom;

lazy_static! {
    static ref IDENT_RE: Regex = Regex::new(
        r"^[a-z][a-z0-9]*$"
    ).safe_unwrap("built-in Regex is broken. Please file a bug");
}

lazy_static! {
    static ref IDENT_HYPHEN_RE: Regex = Regex::new(
        r"^[a-z][a-z0-9-]*$"
    ).safe_unwrap("built-in Regex is broken. Please file a bug");
}

lazy_static! {
    static ref IDENT_UNDERSCORE_RE: Regex = Regex::new(
        r"^[a-z][a-z0-9_]*$"
    ).safe_unwrap("built-in Regex is broken. Please file a bug");
}

lazy_static! {
    static ref ENUM_EXPR_RE: Regex = Regex::new(
        r"^ENUM.*\(((?:[A-Z][A-Z0-9]*,?)*)\)$"
    ).safe_unwrap("built-in Regex is broken. Please file a bug");
}

lazy_static! {
    static ref CONSTRAINT_RE: Regex = Regex::new(
        r"^(:?(?:NULLABLE|UNIQUE),?)*$"
    ).safe_unwrap("built-in Regex is broken. Please file a bug");
}

#[derive(Clone, Debug, Eq, PartialEq)]
struct CsvxMetadata {
    pub table_name: String,
    pub date: NaiveDate,
    pub schema: String,
    pub csvx_version: usize,
}

impl CsvxMetadata {
    fn is_schema(&self) -> bool {
        self.schema == "csvx-schema"
    }
}

#[derive(Debug)]
enum SchemaLoadError {
    Csv(csv::Error),
    MissingHeader,
    BadHeader,
    BadIdentifier(usize, String),
    BadType(usize, ColumnTypeError),
    BadConstraints(usize, ColumnConstraintsError),
}

#[derive(Clone, Debug)]
enum ColumnTypeError {
    UnknownType,
}

#[derive(Clone, Debug)]
enum ColumnType {
    String,
    Bool,
    Integer,
    Enum(Vec<String>),
    Decimal,
    Date,
    DateTime,
    Time,
}

#[derive(Clone, Debug)]
struct ColumnConstraints {
    nullable: bool,
    unique: bool,
}

impl Default for ColumnConstraints {
    fn default() -> ColumnConstraints {
        ColumnConstraints {
            nullable: false,
            unique: false,
        }
    }
}

#[derive(Clone, Debug)]
enum ColumnConstraintsError {
    MalformedConstraint,
    UnknownConstraint(String),
}

impl<S> TryFrom<S> for ColumnConstraints
    where S: AsRef<str>
{
    type Err = ColumnConstraintsError;

    fn try_from(s: S) -> Result<ColumnConstraints, Self::Err> {
        if !CONSTRAINT_RE.is_match(s.as_ref()) {
            return Err(ColumnConstraintsError::MalformedConstraint);
        }

        let mut ccs = ColumnConstraints::default();

        if s.as_ref() == "" {
            return Ok(ccs);
        }

        for fragment in s.as_ref().split(',') {
            match fragment.as_ref() {
                "NULLABLE" => {
                    ccs.nullable = true;
                }
                "UNIQUE" => {
                    ccs.unique = true;
                }
                _ => return Err(ColumnConstraintsError::UnknownConstraint(s.as_ref().to_string())),
            }

        }

        Ok(ccs)
    }
}

impl<S> TryFrom<S> for ColumnType
    where S: AsRef<str>
{
    type Err = ColumnTypeError;

    fn try_from(s: S) -> Result<ColumnType, Self::Err> {
        match s.as_ref() {
            "STRING" => Ok(ColumnType::String),
            "BOOL" => Ok(ColumnType::Bool),
            "INTEGER" => Ok(ColumnType::Integer),
            "DECIMAL" => Ok(ColumnType::Decimal),
            "DATE" => Ok(ColumnType::Date),
            "DATETIME" => Ok(ColumnType::DateTime),
            "TIME" => Ok(ColumnType::Time),
            _ if ENUM_EXPR_RE.is_match(s.as_ref()) => {
                let variants: Vec<_> = ENUM_EXPR_RE
                    .captures(s.as_ref())
                    .safe_unwrap("match already exists")
                    .get(1)
                    .safe_unwrap("group 1 exists in regex")
                    .as_str()
                    .split(',')
                    .map(|s| s.to_owned())
                    .collect();

                Ok(ColumnType::Enum(variants))
            }
            _ => return Err(ColumnTypeError::UnknownType),

        }
    }
}

#[derive(Clone, Debug)]
struct CsvxColumnType {
    id: String,
    ty: ColumnType,
    constraints: ColumnConstraints,
    description: String,
}

#[derive(Clone, Debug)]
struct CsvxSchema {
    columns: Vec<CsvxColumnType>,
}

impl From<csv::Error> for SchemaLoadError {
    fn from(e: csv::Error) -> SchemaLoadError {
        SchemaLoadError::Csv(e)
    }
}

impl CsvxSchema {
    fn from_file<P: AsRef<path::Path>>(filename: P) -> Result<CsvxSchema, SchemaLoadError> {
        let mut rdr = csv::Reader::from_file(filename)?.has_headers(false);

        let mut it = rdr.decode();
        let header: Option<Result<(String, String, String, String), _>> = it.next();

        let mut columns = Vec::new();

        match header {
            None => return Err(SchemaLoadError::MissingHeader),
            Some(res) => {
                let fields = res?;

                println!("{:?}", fields);

                if fields.0 != "id" || fields.1 != "type" || fields.2 != "constraints" ||
                   fields.3 != "description" {

                    return Err(SchemaLoadError::BadHeader);
                }

                for (recno, rec) in it.enumerate() {
                    let (id, ty, constraints, desc) = rec?;
                    let lineno = recno + 2;

                    // check identifier
                    if !IDENT_UNDERSCORE_RE.is_match(&id.as_str()) {
                        return Err(SchemaLoadError::BadIdentifier(lineno, id));
                    }

                    // create type
                    let col_type = match ColumnType::try_from(ty.as_str()) {
                        Ok(v) => v,
                        Err(e) => return Err(SchemaLoadError::BadType(lineno, e)),
                    };

                    // create constraints
                    let col_constraints = match ColumnConstraints::try_from(constraints.as_str()) {
                        Ok(v) => v,
                        Err(e) => return Err(SchemaLoadError::BadConstraints(lineno, e)),
                    };

                    let col = CsvxColumnType {
                        id: id,
                        ty: col_type,
                        constraints: col_constraints,
                        description: desc,
                    };

                    columns.push(col)
                }

                Ok(CsvxSchema { columns: columns })
            }
        }

    }
}

#[inline]
fn cap<T>(c: &regex::Captures, idx: usize) -> T
    where T: std::str::FromStr,
          T::Err: std::fmt::Debug
{
    println!("TRYING: {:?}", c.get(idx));

    c.get(idx)
        .safe_unwrap("valid group")
        .as_str()
        .parse()
        .safe_unwrap("already validated through regex")

}

fn parse_filename<S: AsRef<str>>(filename: S) -> Option<CsvxMetadata> {
    lazy_static! {
        // `tablename_date_schema-schemaversion_csvxversion.csvx`
        static ref FN_RE: Regex = Regex::new(
            r"^([a-z][a-z0-9-]*)_(\d{4})(\d{2})(\d{2})_([a-z][a-z0-9-]*)_(\d+).csv$"
        ).expect("built-in Regex is broken. Please file a bug");
    }

    match FN_RE.captures(filename.as_ref()) {
        Some(caps) => {
            let table_name = caps.get(1)
                .safe_unwrap("known group")
                .as_str()
                .to_string();
            let year = cap(&caps, 2);
            let month = cap(&caps, 3);
            let day = cap(&caps, 4);
            let schema = caps.get(5)
                .safe_unwrap("known group")
                .as_str()
                .to_string();
            let csvx_version = cap(&caps, 6);

            Some(CsvxMetadata {
                     table_name: table_name,
                     date: NaiveDate::from_ymd(year, month, day),
                     schema: schema,
                     csvx_version: csvx_version,
                 })
        }
        None => None,
    }
}

fn main() {
    let app = App::new("csvx")
        .version("4.0.0")
        .about("csvx version 2 utility")
        .subcommand(SubCommand::with_name("check")
                        .about("Check csvx files for conformance")
                        .arg(Arg::with_name("schema_file")
                                 .help("Schema file to check against")
                                 .required(true)
                                 .takes_value(true))
                        .arg(Arg::with_name("input_files")
                                 .help("Input files to check")
                                 .multiple(true)
                                 .takes_value(true)));
    let m = app.clone().get_matches();

    match m.subcommand {
        Some(ref cmd) if cmd.name == "check" => {
            let schema_file = cmd.matches
                .value_of("schema_file")
                .safe_unwrap("required argument");

            let meta = parse_filename(schema_file).expect("filename is not in valid format");

            if !meta.is_schema() {
                println!("The supplied file {} is not a csvx schema (wrong filename)",
                         schema_file);
                return;
            }

            // load schema
            let schema = CsvxSchema::from_file(schema_file).unwrap();

            println!("{:?}", schema);
        }
        _ => app.write_help(&mut io::stdout()).unwrap(),
    }
}

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

    use chrono::NaiveDate;

    #[test]
    fn filename_parsing_rejects_invalid() {
        assert_eq!(parse_filename("asdf"), None);
        assert_eq!(parse_filename(""), None);
        assert_eq!(parse_filename("test.csv"), None);
        assert_eq!(parse_filename("test.csv"), None);
    }

    #[test]
    fn filename_parsing_parses_valid() {
        assert_eq!(parse_filename("zoo-nyc_20170401_animals-2_3.csv").unwrap(),
                   CsvxMetadata {
                       table_name: "zoo-nyc".to_owned(),
                       date: NaiveDate::from_ymd(2017, 04, 01),
                       schema: "animals-2".to_owned(),
                       csvx_version: 3,
                   });
    }

}
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// This is a script to deploy and execute a binary on an iOS simulator.
// The primary use of this is to be able to run unit tests on the simulator and
// retrieve the results.
//
// To do this through Cargo instead, use Dinghy
// (https://github.com/snipsco/dinghy): cargo dinghy install, then cargo dinghy
// test.

use std::env;
use std::fs::{self, File};
use std::io::Write;
use std::path::Path;
use std::process;
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with: {}", stringify!($e), e),
    })
}

// Step one: Wrap as an app
fn package_as_simulator_app(crate_name: &str, test_binary_path: &Path) {
    println!("Packaging simulator app");
    drop(fs::remove_dir_all("ios_simulator_app"));
    t!(fs::create_dir("ios_simulator_app"));
    t!(fs::copy(test_binary_path,
                Path::new("ios_simulator_app").join(crate_name)));

    let mut f = t!(File::create("ios_simulator_app/Info.plist"));
    t!(f.write_all(format!(r#"
        <?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE plist PUBLIC
                "-//Apple//DTD PLIST 1.0//EN"
                "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
        <plist version="1.0">
            <dict>
                <key>CFBundleExecutable</key>
                <string>{}</string>
                <key>CFBundleIdentifier</key>
                <string>com.rust.unittests</string>
            </dict>
        </plist>
    "#, crate_name).as_bytes()));
}

// Step two: Start the iOS simulator
fn start_simulator() {
    println!("Looking for iOS simulator");
    let output = t!(Command::new("xcrun").arg("simctl").arg("list").output());
    assert!(output.status.success());
    let mut simulator_exists = false;
    let mut simulator_booted = false;
    let mut found_rust_sim = false;
    let stdout = t!(String::from_utf8(output.stdout));
    for line in stdout.lines() {
        if line.contains("rust_ios") {
            if found_rust_sim {
                panic!("Duplicate rust_ios simulators found. Please \
                        double-check xcrun simctl list.");
            }
            simulator_exists = true;
            simulator_booted = line.contains("(Booted)");
            found_rust_sim = true;
        }
    }

    if simulator_exists == false {
        println!("Creating iOS simulator");
        Command::new("xcrun")
                .arg("simctl")
                .arg("create")
                .arg("rust_ios")
                .arg("com.apple.CoreSimulator.SimDeviceType.iPhone-SE")
                .arg("com.apple.CoreSimulator.SimRuntime.iOS-10-2")
                .check_status();
    } else if simulator_booted == true {
        println!("Shutting down already-booted simulator");
        Command::new("xcrun")
                .arg("simctl")
                .arg("shutdown")
                .arg("rust_ios")
                .check_status();
    }

    println!("Starting iOS simulator");
    // We can't uninstall the app (if present) as that will hang if the
    // simulator isn't completely booted; just erase the simulator instead.
    Command::new("xcrun").arg("simctl").arg("erase").arg("rust_ios").check_status();
    Command::new("xcrun").arg("simctl").arg("boot").arg("rust_ios").check_status();
}

// Step three: Install the app
fn install_app_to_simulator() {
    println!("Installing app to simulator");
    Command::new("xcrun")
            .arg("simctl")
            .arg("install")
            .arg("booted")
            .arg("ios_simulator_app/")
            .check_status();
}

// Step four: Run the app
fn run_app_on_simulator() {
    println!("Running app");
    let output = t!(Command::new("xcrun")
                    .arg("simctl")
                    .arg("launch")
                    .arg("--console")
                    .arg("booted")
                    .arg("com.rust.unittests")
                    .arg("--color")
                    .arg("never")
                    .output());

    println!("stdout --\n{}\n", String::from_utf8_lossy(&output.stdout));
    println!("stderr --\n{}\n", String::from_utf8_lossy(&output.stderr));

    let stdout = String::from_utf8_lossy(&output.stdout);
    let passed = stdout.lines()
                       .find(|l| l.contains("test result"))
                       .map(|l| l.contains(" 0 failed"))
                       .unwrap_or(false);

    println!("Shutting down simulator");
    Command::new("xcrun")
        .arg("simctl")
        .arg("shutdown")
        .arg("rust_ios")
        .check_status();
    if !passed {
        panic!("tests didn't pass");
    }
}

trait CheckStatus {
    fn check_status(&mut self);
}

impl CheckStatus for Command {
    fn check_status(&mut self) {
        println!("\trunning: {:?}", self);
        assert!(t!(self.status()).success());
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        println!("Usage: {} <executable>", args[0]);
        process::exit(-1);
    }

    let test_binary_path = Path::new(&args[1]);
    let crate_name = test_binary_path.file_name().unwrap();

    package_as_simulator_app(crate_name.to_str().unwrap(), test_binary_path);
    start_simulator();
    install_app_to_simulator();
    run_app_on_simulator();
}
<commit_msg>CI: Stream test output on iOS<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// This is a script to deploy and execute a binary on an iOS simulator.
// The primary use of this is to be able to run unit tests on the simulator and
// retrieve the results.
//
// To do this through Cargo instead, use Dinghy
// (https://github.com/snipsco/dinghy): cargo dinghy install, then cargo dinghy
// test.

use std::env;
use std::fs::{self, File};
use std::io::Write;
use std::path::Path;
use std::thread;
use std::process::{self, Command, Stdio};

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with: {}", stringify!($e), e),
    })
}

// Step one: Wrap as an app
fn package_as_simulator_app(crate_name: &str, test_binary_path: &Path) {
    println!("Packaging simulator app");
    drop(fs::remove_dir_all("ios_simulator_app"));
    t!(fs::create_dir("ios_simulator_app"));
    t!(fs::copy(test_binary_path,
                Path::new("ios_simulator_app").join(crate_name)));

    let mut f = t!(File::create("ios_simulator_app/Info.plist"));
    t!(f.write_all(format!(r#"
        <?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE plist PUBLIC
                "-//Apple//DTD PLIST 1.0//EN"
                "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
        <plist version="1.0">
            <dict>
                <key>CFBundleExecutable</key>
                <string>{}</string>
                <key>CFBundleIdentifier</key>
                <string>com.rust.unittests</string>
            </dict>
        </plist>
    "#, crate_name).as_bytes()));
}

// Step two: Start the iOS simulator
fn start_simulator() {
    println!("Looking for iOS simulator");
    let output = t!(Command::new("xcrun").arg("simctl").arg("list").output());
    assert!(output.status.success());
    let mut simulator_exists = false;
    let mut simulator_booted = false;
    let mut found_rust_sim = false;
    let stdout = t!(String::from_utf8(output.stdout));
    for line in stdout.lines() {
        if line.contains("rust_ios") {
            if found_rust_sim {
                panic!("Duplicate rust_ios simulators found. Please \
                        double-check xcrun simctl list.");
            }
            simulator_exists = true;
            simulator_booted = line.contains("(Booted)");
            found_rust_sim = true;
        }
    }

    if simulator_exists == false {
        println!("Creating iOS simulator");
        Command::new("xcrun")
                .arg("simctl")
                .arg("create")
                .arg("rust_ios")
                .arg("com.apple.CoreSimulator.SimDeviceType.iPhone-SE")
                .arg("com.apple.CoreSimulator.SimRuntime.iOS-10-2")
                .check_status();
    } else if simulator_booted == true {
        println!("Shutting down already-booted simulator");
        Command::new("xcrun")
                .arg("simctl")
                .arg("shutdown")
                .arg("rust_ios")
                .check_status();
    }

    println!("Starting iOS simulator");
    // We can't uninstall the app (if present) as that will hang if the
    // simulator isn't completely booted; just erase the simulator instead.
    Command::new("xcrun").arg("simctl").arg("erase").arg("rust_ios").check_status();
    Command::new("xcrun").arg("simctl").arg("boot").arg("rust_ios").check_status();
}

// Step three: Install the app
fn install_app_to_simulator() {
    println!("Installing app to simulator");
    Command::new("xcrun")
            .arg("simctl")
            .arg("install")
            .arg("booted")
            .arg("ios_simulator_app/")
            .check_status();
}

// Step four: Run the app
fn run_app_on_simulator() {
    use std::io::{self, Read, Write};

    println!("Running app");
    let mut child = t!(Command::new("xcrun")
                    .arg("simctl")
                    .arg("launch")
                    .arg("--console")
                    .arg("booted")
                    .arg("com.rust.unittests")
                    .arg("--color")
                    .arg("never")
                    .stdout(Stdio::piped())
                    .stderr(Stdio::piped())
                    .spawn());

    let stdout = child.stdout.take().unwrap();
    let stderr = child.stderr.take().unwrap();

    let th = thread::spawn(move || {
        let mut out = vec![];

        for b in stdout.bytes() {
            let b = b.unwrap();
            out.push(b);
            let out = [b];
            io::stdout().write(&out[..]).unwrap();
        }

        out
    });

    thread::spawn(move || {
        for b in stderr.bytes() {
            let out = [b.unwrap()];
            io::stderr().write(&out[..]).unwrap();
        }
    });

    println!("Waiting for cmd to finish");
    child.wait().unwrap();

    println!("Waiting for stdout");
    let stdout = th.join().unwrap();
    let stdout = String::from_utf8_lossy(&stdout);
    let passed = stdout.lines()
                       .find(|l| l.contains("test result"))
                       .map(|l| l.contains(" 0 failed"))
                       .unwrap_or(false);

    println!("Shutting down simulator");
    Command::new("xcrun")
        .arg("simctl")
        .arg("shutdown")
        .arg("rust_ios")
        .check_status();
    if !passed {
        panic!("tests didn't pass");
    }
}

trait CheckStatus {
    fn check_status(&mut self);
}

impl CheckStatus for Command {
    fn check_status(&mut self) {
        println!("\trunning: {:?}", self);
        assert!(t!(self.status()).success());
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        println!("Usage: {} <executable>", args[0]);
        process::exit(-1);
    }

    let test_binary_path = Path::new(&args[1]);
    let crate_name = test_binary_path.file_name().unwrap();

    package_as_simulator_app(crate_name.to_str().unwrap(), test_binary_path);
    start_simulator();
    install_app_to_simulator();
    run_app_on_simulator();
}
<|endoftext|>


<commit_before><commit_msg>Fix TableIndicator bit offset<commit_after><|endoftext|>


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

use std::sync::Arc;
use std::thread;
use std::time;

use crate::chain;
use crate::common::types::{SyncState, SyncStatus};
use crate::core::pow::Difficulty;
use crate::grin::sync::body_sync::BodySync;
use crate::grin::sync::header_sync::HeaderSync;
use crate::grin::sync::state_sync::StateSync;
use crate::p2p;
use crate::util::{Mutex, StopState};

pub fn run_sync(
	sync_state: Arc<SyncState>,
	peers: Arc<p2p::Peers>,
	chain: Arc<chain::Chain>,
	stop_state: Arc<Mutex<StopState>>,
) {
	let _ = thread::Builder::new()
		.name("sync".to_string())
		.spawn(move || {
			let runner = SyncRunner::new(sync_state, peers, chain, stop_state);
			runner.sync_loop();
		});
}

pub struct SyncRunner {
	sync_state: Arc<SyncState>,
	peers: Arc<p2p::Peers>,
	chain: Arc<chain::Chain>,
	stop_state: Arc<Mutex<StopState>>,
}

impl SyncRunner {
	fn new(
		sync_state: Arc<SyncState>,
		peers: Arc<p2p::Peers>,
		chain: Arc<chain::Chain>,
		stop_state: Arc<Mutex<StopState>>,
	) -> SyncRunner {
		SyncRunner {
			sync_state,
			peers,
			chain,
			stop_state,
		}
	}

	fn wait_for_min_peers(&self) {
		// Initial sleep to give us time to peer with some nodes.
		// Note: Even if we have skip peer wait we need to wait a
		// short period of time for tests to do the right thing.
		let wait_secs = if let SyncStatus::AwaitingPeers(true) = self.sync_state.status() {
			30
		} else {
			3
		};

		let head = self.chain.head().unwrap();

		let mut n = 0;
		const MIN_PEERS: usize = 3;
		loop {
			let wp = self.peers.more_work_peers();
			// exit loop when:
			// * we have more than MIN_PEERS more_work peers
			// * we are synced already, e.g. grin was quickly restarted
			// * timeout
			if wp.len() > MIN_PEERS
				|| (wp.len() == 0
					&& self.peers.enough_peers()
					&& head.total_difficulty > Difficulty::zero())
				|| n > wait_secs
			{
				break;
			}
			thread::sleep(time::Duration::from_secs(1));
			n += 1;
		}
	}

	/// Starts the syncing loop, just spawns two threads that loop forever
	fn sync_loop(&self) {
		// Wait for connections reach at least MIN_PEERS
		self.wait_for_min_peers();

		// Our 3 main sync stages
		let mut header_sync = HeaderSync::new(
			self.sync_state.clone(),
			self.peers.clone(),
			self.chain.clone(),
		);
		let mut body_sync = BodySync::new(
			self.sync_state.clone(),
			self.peers.clone(),
			self.chain.clone(),
		);
		let mut state_sync = StateSync::new(
			self.sync_state.clone(),
			self.peers.clone(),
			self.chain.clone(),
		);

		// Highest height seen on the network, generally useful for a fast test on
		// whether some sync is needed
		let mut highest_height = 0;

		// Main syncing loop
		loop {
			if self.stop_state.lock().is_stopped() {
				break;
			}

			thread::sleep(time::Duration::from_millis(10));

			// check whether syncing is generally needed, when we compare our state with others
			let (syncing, most_work_height) = self.needs_syncing();

			if most_work_height > 0 {
				// we can occasionally get a most work height of 0 if read locks fail
				highest_height = most_work_height;
			}

			// quick short-circuit (and a decent sleep) if no syncing is needed
			if !syncing {
				self.sync_state.update(SyncStatus::NoSync);
				thread::sleep(time::Duration::from_secs(10));
				continue;
			}

			// if syncing is needed
			let head = self.chain.head().unwrap();
			let tail = self.chain.tail().unwrap_or_else(|_| head.clone());
			let header_head = self.chain.header_head().unwrap();

			// run each sync stage, each of them deciding whether they're needed
			// except for state sync that only runs if body sync return true (means txhashset is needed)
			header_sync.check_run(&header_head, highest_height);

			let mut check_state_sync = false;
			match self.sync_state.status() {
				SyncStatus::TxHashsetDownload { .. }
				| SyncStatus::TxHashsetSetup
				| SyncStatus::TxHashsetValidation { .. }
				| SyncStatus::TxHashsetSave
				| SyncStatus::TxHashsetDone => check_state_sync = true,
				_ => {
					// skip body sync if header chain is not synced.
					if header_head.height < highest_height {
						continue;
					}

					if body_sync.check_run(&head, highest_height) {
						check_state_sync = true;
					}
				}
			}

			if check_state_sync {
				state_sync.check_run(&header_head, &head, &tail, highest_height);
			}
		}
	}

	/// Whether we're currently syncing the chain or we're fully caught up and
	/// just receiving blocks through gossip.
	fn needs_syncing(&self) -> (bool, u64) {
		let local_diff = self.chain.head().unwrap().total_difficulty;
		let mut is_syncing = self.sync_state.is_syncing();
		let peer = self.peers.most_work_peer();

		let peer_info = if let Some(p) = peer {
			p.info.clone()
		} else {
			warn!("sync: no peers available, disabling sync");
			return (false, 0);
		};

		// if we're already syncing, we're caught up if no peer has a higher
		// difficulty than us
		if is_syncing {
			if peer_info.total_difficulty() <= local_diff {
				let ch = self.chain.head().unwrap();
				info!(
					"synchronized at {} @ {} [{}]",
					local_diff.to_num(),
					ch.height,
					ch.last_block_h
				);
				is_syncing = false;
			}
		} else {
			// sum the last 5 difficulties to give us the threshold
			let threshold = self
				.chain
				.difficulty_iter()
				.map(|x| x.difficulty)
				.take(5)
				.fold(Difficulty::zero(), |sum, val| sum + val);

			let peer_diff = peer_info.total_difficulty();
			if peer_diff > local_diff.clone() + threshold.clone() {
				info!(
					"sync: total_difficulty {}, peer_difficulty {}, threshold {} (last 5 blocks), enabling sync",
					local_diff,
					peer_diff,
					threshold,
				);
				is_syncing = true;
			}
		}
		(is_syncing, peer_info.height())
	}
}
<commit_msg>wait_for_min_peers should continue waiting if none connected (#2326)<commit_after>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::Arc;
use std::thread;
use std::time;

use crate::chain;
use crate::common::types::{SyncState, SyncStatus};
use crate::core::global;
use crate::core::pow::Difficulty;
use crate::grin::sync::body_sync::BodySync;
use crate::grin::sync::header_sync::HeaderSync;
use crate::grin::sync::state_sync::StateSync;
use crate::p2p;
use crate::util::{Mutex, StopState};

pub fn run_sync(
	sync_state: Arc<SyncState>,
	peers: Arc<p2p::Peers>,
	chain: Arc<chain::Chain>,
	stop_state: Arc<Mutex<StopState>>,
) {
	let _ = thread::Builder::new()
		.name("sync".to_string())
		.spawn(move || {
			let runner = SyncRunner::new(sync_state, peers, chain, stop_state);
			runner.sync_loop();
		});
}

pub struct SyncRunner {
	sync_state: Arc<SyncState>,
	peers: Arc<p2p::Peers>,
	chain: Arc<chain::Chain>,
	stop_state: Arc<Mutex<StopState>>,
}

impl SyncRunner {
	fn new(
		sync_state: Arc<SyncState>,
		peers: Arc<p2p::Peers>,
		chain: Arc<chain::Chain>,
		stop_state: Arc<Mutex<StopState>>,
	) -> SyncRunner {
		SyncRunner {
			sync_state,
			peers,
			chain,
			stop_state,
		}
	}

	fn wait_for_min_peers(&self) {
		// Initial sleep to give us time to peer with some nodes.
		// Note: Even if we have skip peer wait we need to wait a
		// short period of time for tests to do the right thing.
		let wait_secs = if let SyncStatus::AwaitingPeers(true) = self.sync_state.status() {
			30
		} else {
			3
		};

		let head = self.chain.head().unwrap();

		let mut n = 0;
		const MIN_PEERS: usize = 3;
		loop {
			let wp = self.peers.more_work_peers();
			// exit loop when:
			// * we have more than MIN_PEERS more_work peers
			// * we are synced already, e.g. grin was quickly restarted
			// * timeout
			if wp.len() > MIN_PEERS
				|| (wp.len() == 0
					&& self.peers.enough_peers()
					&& head.total_difficulty > Difficulty::zero())
				|| n > wait_secs
			{
				if wp.len() > 0 || !global::is_production_mode() {
					break;
				}
			}
			thread::sleep(time::Duration::from_secs(1));
			n += 1;
		}
	}

	/// Starts the syncing loop, just spawns two threads that loop forever
	fn sync_loop(&self) {
		// Wait for connections reach at least MIN_PEERS
		self.wait_for_min_peers();

		// Our 3 main sync stages
		let mut header_sync = HeaderSync::new(
			self.sync_state.clone(),
			self.peers.clone(),
			self.chain.clone(),
		);
		let mut body_sync = BodySync::new(
			self.sync_state.clone(),
			self.peers.clone(),
			self.chain.clone(),
		);
		let mut state_sync = StateSync::new(
			self.sync_state.clone(),
			self.peers.clone(),
			self.chain.clone(),
		);

		// Highest height seen on the network, generally useful for a fast test on
		// whether some sync is needed
		let mut highest_height = 0;

		// Main syncing loop
		loop {
			if self.stop_state.lock().is_stopped() {
				break;
			}

			thread::sleep(time::Duration::from_millis(10));

			// check whether syncing is generally needed, when we compare our state with others
			let (syncing, most_work_height) = self.needs_syncing();

			if most_work_height > 0 {
				// we can occasionally get a most work height of 0 if read locks fail
				highest_height = most_work_height;
			}

			// quick short-circuit (and a decent sleep) if no syncing is needed
			if !syncing {
				self.sync_state.update(SyncStatus::NoSync);
				thread::sleep(time::Duration::from_secs(10));
				continue;
			}

			// if syncing is needed
			let head = self.chain.head().unwrap();
			let tail = self.chain.tail().unwrap_or_else(|_| head.clone());
			let header_head = self.chain.header_head().unwrap();

			// run each sync stage, each of them deciding whether they're needed
			// except for state sync that only runs if body sync return true (means txhashset is needed)
			header_sync.check_run(&header_head, highest_height);

			let mut check_state_sync = false;
			match self.sync_state.status() {
				SyncStatus::TxHashsetDownload { .. }
				| SyncStatus::TxHashsetSetup
				| SyncStatus::TxHashsetValidation { .. }
				| SyncStatus::TxHashsetSave
				| SyncStatus::TxHashsetDone => check_state_sync = true,
				_ => {
					// skip body sync if header chain is not synced.
					if header_head.height < highest_height {
						continue;
					}

					if body_sync.check_run(&head, highest_height) {
						check_state_sync = true;
					}
				}
			}

			if check_state_sync {
				state_sync.check_run(&header_head, &head, &tail, highest_height);
			}
		}
	}

	/// Whether we're currently syncing the chain or we're fully caught up and
	/// just receiving blocks through gossip.
	fn needs_syncing(&self) -> (bool, u64) {
		let local_diff = self.chain.head().unwrap().total_difficulty;
		let mut is_syncing = self.sync_state.is_syncing();
		let peer = self.peers.most_work_peer();

		let peer_info = if let Some(p) = peer {
			p.info.clone()
		} else {
			warn!("sync: no peers available, disabling sync");
			return (false, 0);
		};

		// if we're already syncing, we're caught up if no peer has a higher
		// difficulty than us
		if is_syncing {
			if peer_info.total_difficulty() <= local_diff {
				let ch = self.chain.head().unwrap();
				info!(
					"synchronized at {} @ {} [{}]",
					local_diff.to_num(),
					ch.height,
					ch.last_block_h
				);
				is_syncing = false;
			}
		} else {
			// sum the last 5 difficulties to give us the threshold
			let threshold = self
				.chain
				.difficulty_iter()
				.map(|x| x.difficulty)
				.take(5)
				.fold(Difficulty::zero(), |sum, val| sum + val);

			let peer_diff = peer_info.total_difficulty();
			if peer_diff > local_diff.clone() + threshold.clone() {
				info!(
					"sync: total_difficulty {}, peer_difficulty {}, threshold {} (last 5 blocks), enabling sync",
					local_diff,
					peer_diff,
					threshold,
				);
				is_syncing = true;
			}
		}
		(is_syncing, peer_info.height())
	}
}
<|endoftext|>