<commit_before>// Rust source (c) 2016 by the Rayon developers. This is ported from
// [JavaScript sources][1] developed by Intel as part of the Parallel
// JS project. The copyright for the original source is reproduced
// below.
//
// Copyright (c) 2011, Intel Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
// - Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//
// [1]: https://github.com/IntelLabs/RiverTrail/blob/master/examples/nbody-webgl/NBody.js

use cgmath::{EuclideanVector, Point3, Vector, Vector3};
use rayon::par_iter::*;
use rand::{Rand, Rng};
use std::f64::NEG_INFINITY;
use std::f64::consts::PI;

const INITIAL_VELOCITY: f64 = 8.0; // set to 0.0 to turn off.

pub struct NBodyBenchmark {
    time: usize,
    bodies: (Vec<Body>, Vec<Body>),
}

#[derive(Copy, Clone, Debug)]
pub struct Body {
    pub position: Point3<f64>,
    pub velocity: Vector3<f64>,
    pub velocity2: Vector3<f64>,
}

impl NBodyBenchmark {
    pub fn new<R: Rng>(num_bodies: usize, rng: &mut R) -> NBodyBenchmark {
        let bodies0: Vec<_> =
            (0..num_bodies)
            .map(|_| {
                let position = Point3 {
                    x: f64::rand(rng).floor() * 40_000.0,
                    y: f64::rand(rng).floor() * 20_000.0,
                    z: (f64::rand(rng).floor() - 0.25) * 50_000.0,
                };

                let velocity = Vector3 {
                    x: (f64::rand(rng) - 0.5) * INITIAL_VELOCITY,
                    y: (f64::rand(rng) - 0.5) * INITIAL_VELOCITY,
                    z: f64::rand(rng) * INITIAL_VELOCITY + 10.0,
                };

                let velocity2 = Vector3 {
                    x: (f64::rand(rng) - 0.5) * INITIAL_VELOCITY,
                    y: (f64::rand(rng) - 0.5) * INITIAL_VELOCITY,
                    z: f64::rand(rng) * INITIAL_VELOCITY,
                };

                Body { position: position, velocity: velocity, velocity2: velocity2 }
            })
            .collect();

        let bodies1 = bodies0.clone();

        NBodyBenchmark {
            time: 0,
            bodies: (bodies0, bodies1),
        }
    }

    pub fn tick_par(&mut self) -> &[Body] {
        let (in_bodies, out_bodies) = if (self.time & 1) == 0 {
            (&self.bodies.0, &mut self.bodies.1)
        } else {
            (&self.bodies.1, &mut self.bodies.0)
        };

        let time = self.time;
        out_bodies.par_iter_mut()
                  .weight(200.0)
                  .zip(&in_bodies[..])
                  .for_each(|(out, prev)| {
                      let (vel, vel2) = next_velocity(time, prev, in_bodies);
                      out.velocity = vel;
                      out.velocity2 = vel2;

                      let next_velocity = vel - vel2;
                      out.position = prev.position + next_velocity;
                  });

        self.time += 1;

        out_bodies
    }

    pub fn tick_par_reduce(&mut self) -> &[Body] {
        let (in_bodies, out_bodies) = if (self.time & 1) == 0 {
            (&self.bodies.0, &mut self.bodies.1)
        } else {
            (&self.bodies.1, &mut self.bodies.0)
        };

        let time = self.time;
        out_bodies.par_iter_mut()
                  .weight(200.0)
                  .zip(&in_bodies[..])
                  .for_each(|(out, prev)| {
                      let (vel, vel2) = next_velocity_par(time, prev, in_bodies);
                      out.velocity = vel;
                      out.velocity2 = vel2;

                      let next_velocity = vel - vel2;
                      out.position = prev.position + next_velocity;
                  });

        self.time += 1;

        out_bodies
    }

    pub fn tick_seq(&mut self) -> &[Body] {
        let (in_bodies, out_bodies) = if (self.time & 1) == 0 {
            (&self.bodies.0, &mut self.bodies.1)
        } else {
            (&self.bodies.1, &mut self.bodies.0)
        };

        let time = self.time;
        for (out, prev) in out_bodies.iter_mut().zip(&in_bodies[..]) {
            let (vel, vel2) = next_velocity(time, prev, in_bodies);
            out.velocity = vel;
            out.velocity2 = vel2;

            let next_velocity = vel - vel2;
            out.position = prev.position + next_velocity;
        }

        self.time += 1;

        out_bodies
    }
}

/// Compute next velocity of `prev`
fn next_velocity(time: usize, prev: &Body, bodies: &[Body]) -> (Vector3<f64>, Vector3<f64>) {
    let time = time as f64;
    let center = Point3 {
        x: (time / 22.0).cos() * -4200.0,
        y: (time / 14.0).sin() * 9200.0,
        z: (time / 27.0).sin() * 6000.0,
    };

    // pull to center
    let max_distance = 3400.0;
    let pull_strength = 0.042;

    // zones
    let zone = 400.0;
    let repel = 100.0;
    let align = 300.0;
    let attract = 100.0;

    let (speed_limit, attract_power);
    if time < 500.0 {
        speed_limit = 2000.0;
        attract_power = 100.9;
    } else {
        speed_limit = 0.2;
        attract_power = 20.9;
    }

    let zone_sqrd = 3.0 * (zone * zone);

    let mut acc = Vector3::zero();
    let mut acc2 = Vector3::zero();

    let dir_to_center = center - prev.position;
    let dist_to_center = dir_to_center.length();

    // orient to center
    if dist_to_center > max_distance {
        let velc = if time < 200.0 {
            0.2
        } else {
            (dist_to_center - max_distance) * pull_strength
        };

        let diff = (dir_to_center / dist_to_center) * velc;
        acc += diff;
    }

    // TODO -- parallelize this loop too? would be easy enough, it's just a reduction
    // Just have to factor things so that `tick_seq` doesn't do it in parallel.
    for body in bodies {
        let r = body.position - prev.position;

        // make sure we are not testing the particle against its own position
        let are_same = r == Vector3::zero();

        let dist_sqrd = r.length2();

        if dist_sqrd < zone_sqrd && !are_same {
            let length = dist_sqrd.sqrt();
            let percent = dist_sqrd / zone_sqrd;

            if dist_sqrd < repel {
                let f = (repel / percent - 1.0) * 0.025;
                let normal = (r / length) * f;
                acc += normal;
                acc2 += normal;
            } else if dist_sqrd < align {
                let thresh_delta = align - repel;
                let adjusted_percent = (percent - repel) / thresh_delta;
                let q = (0.5 - (adjusted_percent * PI * 2.0).cos() * 0.5 + 0.5) * 100.9;

                // normalize vel2 and multiply by factor
                let vel2_length = body.velocity2.length();
                let vel2 = (body.velocity2 / vel2_length) * q;

                // normalize own velocity
                let vel_length = prev.velocity.length();
                let vel = (prev.velocity / vel_length) * q;

                acc += vel2;
                acc2 += vel;
            }

            if dist_sqrd > attract { // attract
                let thresh_delta2 = 1.0 - attract;
                let adjusted_percent2 = (percent - attract) / thresh_delta2;
                let c = (1.0 - ((adjusted_percent2 * PI * 2.0).cos() * 0.5 + 0.5)) * attract_power;

                // normalize the distance vector
                let d = (r / length) * c;

                acc += d;
                acc2 -= d;
            }
        }
    }

    // Speed limits
    if time > 500.0 {
        let acc_squared = acc.length2();
        if acc_squared > speed_limit {
            acc *= 0.015;
        }

        let acc_squared2 = acc2.length2();
        if acc_squared2 > speed_limit {
            acc2 *= 0.015;
        }
    }

    let mut new = prev.velocity + acc;
    let mut new2 = prev.velocity2 + acc2;

    if time < 500.0 {
        let acs = new2.length2();
        if acs > speed_limit {
            new2 *= 0.15;
        }

        let acs2 = new.length2();
        if acs2 > speed_limit {
            new *= 0.15;
        }
    }

    (new, new2)
}

/// Compute next velocity of `prev`
fn next_velocity_par(time: usize, prev: &Body, bodies: &[Body])
                     -> (Vector3<f64>, Vector3<f64>) {
    let time = time as f64;
    let center = Point3 {
        x: (time / 22.0).cos() * -4200.0,
        y: (time / 14.0).sin() * 9200.0,
        z: (time / 27.0).sin() * 6000.0,
    };

    // pull to center
    let max_distance = 3400.0;
    let pull_strength = 0.042;

    // zones
    let zone = 400.0;
    let repel = 100.0;
    let align = 300.0;
    let attract = 100.0;

    let (speed_limit, attract_power);
    if time < 500.0 {
        speed_limit = 2000.0;
        attract_power = 100.9;
    } else {
        speed_limit = 0.2;
        attract_power = 20.9;
    }

    let zone_sqrd = 3.0 * (zone * zone);

    let mut acc = Vector3::zero();
    let mut acc2 = Vector3::zero();

    let dir_to_center = center - prev.position;
    let dist_to_center = dir_to_center.length();

    // orient to center
    if dist_to_center > max_distance {
        let velc = if time < 200.0 {
            0.2
        } else {
            (dist_to_center - max_distance) * pull_strength
        };

        let diff = (dir_to_center / dist_to_center) * velc;
        acc += diff;
    }

    let (diff, diff2) =
        bodies.par_iter()
              .map(|body| {
                  let r = body.position - prev.position;

                  let mut diff = Vector3::zero();
                  let mut diff2 = Vector3::zero();

                  // make sure we are not testing the particle against its own position
                  let are_same = r == Vector3::zero();

                  let dist_sqrd = r.length2();

                  if dist_sqrd < zone_sqrd && !are_same {
                      let length = dist_sqrd.sqrt();
                      let percent = dist_sqrd / zone_sqrd;

                      if dist_sqrd < repel {
                          let f = (repel / percent - 1.0) * 0.025;
                          let normal = (r / length) * f;
                          diff += normal;
                          diff2 += normal;
                      } else if dist_sqrd < align {
                          let thresh_delta = align - repel;
                          let adjusted_percent = (percent - repel) / thresh_delta;
                          let q = (0.5 - (adjusted_percent * PI * 2.0).cos() * 0.5 + 0.5) * 100.9;

                          // normalize vel2 and multiply by factor
                          let vel2_length = body.velocity2.length();
                          let vel2 = (body.velocity2 / vel2_length) * q;

                          // normalize own velocity
                          let vel_length = prev.velocity.length();
                          let vel = (prev.velocity / vel_length) * q;

                          diff += vel2;
                          diff2 += vel;
                      }

                      if dist_sqrd > attract { // attract
                          let thresh_delta2 = 1.0 - attract;
                          let adjusted_percent2 = (percent - attract) / thresh_delta2;
                          let c = (1.0 - ((adjusted_percent2 * PI * 2.0).cos() * 0.5 + 0.5)) * attract_power;

                          // normalize the distance vector
                          let d = (r / length) * c;

                          diff += d;
                          diff2 -= d;
                      }
                  }

                  (diff, diff2)
              })
              .weight(NEG_INFINITY)
              .reduce_with_identity(
                  (Vector3::zero(), Vector3::zero()),
                  |(diffa, diff2a), (diffb, diff2b)| (diffa + diffb, diff2a + diff2b));

    acc += diff;
    acc2 += diff2;

    // Speed limits
    if time > 500.0 {
        let acc_squared = acc.length2();
        if acc_squared > speed_limit {
            acc *= 0.015;
        }

        let acc_squared2 = acc2.length2();
        if acc_squared2 > speed_limit {
            acc2 *= 0.015;
        }
    }

    let mut new = prev.velocity + acc;
    let mut new2 = prev.velocity2 + acc2;

    if time < 500.0 {
        let acs = new2.length2();
        if acs > speed_limit {
            new2 *= 0.15;
        }

        let acs2 = new.length2();
        if acs2 > speed_limit {
            new *= 0.15;
        }
    }

    (new, new2)
}
<commit_msg>Change sequential version to use fold<commit_after>// Rust source (c) 2016 by the Rayon developers. This is ported from
// [JavaScript sources][1] developed by Intel as part of the Parallel
// JS project. The copyright for the original source is reproduced
// below.
//
// Copyright (c) 2011, Intel Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
// - Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//
// [1]: https://github.com/IntelLabs/RiverTrail/blob/master/examples/nbody-webgl/NBody.js

use cgmath::{EuclideanVector, Point3, Vector, Vector3};
use rayon::par_iter::*;
use rand::{Rand, Rng};
use std::f64::NEG_INFINITY;
use std::f64::consts::PI;

const INITIAL_VELOCITY: f64 = 8.0; // set to 0.0 to turn off.

pub struct NBodyBenchmark {
    time: usize,
    bodies: (Vec<Body>, Vec<Body>),
}

#[derive(Copy, Clone, Debug)]
pub struct Body {
    pub position: Point3<f64>,
    pub velocity: Vector3<f64>,
    pub velocity2: Vector3<f64>,
}

impl NBodyBenchmark {
    pub fn new<R: Rng>(num_bodies: usize, rng: &mut R) -> NBodyBenchmark {
        let bodies0: Vec<_> =
            (0..num_bodies)
            .map(|_| {
                let position = Point3 {
                    x: f64::rand(rng).floor() * 40_000.0,
                    y: f64::rand(rng).floor() * 20_000.0,
                    z: (f64::rand(rng).floor() - 0.25) * 50_000.0,
                };

                let velocity = Vector3 {
                    x: (f64::rand(rng) - 0.5) * INITIAL_VELOCITY,
                    y: (f64::rand(rng) - 0.5) * INITIAL_VELOCITY,
                    z: f64::rand(rng) * INITIAL_VELOCITY + 10.0,
                };

                let velocity2 = Vector3 {
                    x: (f64::rand(rng) - 0.5) * INITIAL_VELOCITY,
                    y: (f64::rand(rng) - 0.5) * INITIAL_VELOCITY,
                    z: f64::rand(rng) * INITIAL_VELOCITY,
                };

                Body { position: position, velocity: velocity, velocity2: velocity2 }
            })
            .collect();

        let bodies1 = bodies0.clone();

        NBodyBenchmark {
            time: 0,
            bodies: (bodies0, bodies1),
        }
    }

    pub fn tick_par(&mut self) -> &[Body] {
        let (in_bodies, out_bodies) = if (self.time & 1) == 0 {
            (&self.bodies.0, &mut self.bodies.1)
        } else {
            (&self.bodies.1, &mut self.bodies.0)
        };

        let time = self.time;
        out_bodies.par_iter_mut()
                  .weight(200.0)
                  .zip(&in_bodies[..])
                  .for_each(|(out, prev)| {
                      let (vel, vel2) = next_velocity(time, prev, in_bodies);
                      out.velocity = vel;
                      out.velocity2 = vel2;

                      let next_velocity = vel - vel2;
                      out.position = prev.position + next_velocity;
                  });

        self.time += 1;

        out_bodies
    }

    pub fn tick_par_reduce(&mut self) -> &[Body] {
        let (in_bodies, out_bodies) = if (self.time & 1) == 0 {
            (&self.bodies.0, &mut self.bodies.1)
        } else {
            (&self.bodies.1, &mut self.bodies.0)
        };

        let time = self.time;
        out_bodies.par_iter_mut()
                  .weight(200.0)
                  .zip(&in_bodies[..])
                  .for_each(|(out, prev)| {
                      let (vel, vel2) = next_velocity_par(time, prev, in_bodies);
                      out.velocity = vel;
                      out.velocity2 = vel2;

                      let next_velocity = vel - vel2;
                      out.position = prev.position + next_velocity;
                  });

        self.time += 1;

        out_bodies
    }

    pub fn tick_seq(&mut self) -> &[Body] {
        let (in_bodies, out_bodies) = if (self.time & 1) == 0 {
            (&self.bodies.0, &mut self.bodies.1)
        } else {
            (&self.bodies.1, &mut self.bodies.0)
        };

        let time = self.time;
        for (out, prev) in out_bodies.iter_mut().zip(&in_bodies[..]) {
            let (vel, vel2) = next_velocity(time, prev, in_bodies);
            out.velocity = vel;
            out.velocity2 = vel2;

            let next_velocity = vel - vel2;
            out.position = prev.position + next_velocity;
        }

        self.time += 1;

        out_bodies
    }
}

/// Compute next velocity of `prev`
fn next_velocity(time: usize, prev: &Body, bodies: &[Body]) -> (Vector3<f64>, Vector3<f64>) {
    let time = time as f64;
    let center = Point3 {
        x: (time / 22.0).cos() * -4200.0,
        y: (time / 14.0).sin() * 9200.0,
        z: (time / 27.0).sin() * 6000.0,
    };

    // pull to center
    let max_distance = 3400.0;
    let pull_strength = 0.042;

    // zones
    let zone = 400.0;
    let repel = 100.0;
    let align = 300.0;
    let attract = 100.0;

    let (speed_limit, attract_power);
    if time < 500.0 {
        speed_limit = 2000.0;
        attract_power = 100.9;
    } else {
        speed_limit = 0.2;
        attract_power = 20.9;
    }

    let zone_sqrd = 3.0 * (zone * zone);

    let mut acc = Vector3::zero();
    let mut acc2 = Vector3::zero();

    let dir_to_center = center - prev.position;
    let dist_to_center = dir_to_center.length();

    // orient to center
    if dist_to_center > max_distance {
        let velc = if time < 200.0 {
            0.2
        } else {
            (dist_to_center - max_distance) * pull_strength
        };

        let diff = (dir_to_center / dist_to_center) * velc;
        acc += diff;
    }

    // TODO -- parallelize this loop too? would be easy enough, it's just a reduction
    // Just have to factor things so that `tick_seq` doesn't do it in parallel.
    let zero: Vector3<f64> = Vector3::zero();
    let (diff, diff2) = bodies
        .iter()
        .fold(
            (zero, zero),
            |(mut diff, mut diff2), body| {
                let r = body.position - prev.position;

                // make sure we are not testing the particle against its own position
                let are_same = r == Vector3::zero();

                let dist_sqrd = r.length2();

                if dist_sqrd < zone_sqrd && !are_same {
                    let length = dist_sqrd.sqrt();
                    let percent = dist_sqrd / zone_sqrd;

                    if dist_sqrd < repel {
                        let f = (repel / percent - 1.0) * 0.025;
                        let normal = (r / length) * f;
                        diff += normal;
                        diff2 += normal;
                    } else if dist_sqrd < align {
                        let thresh_delta = align - repel;
                        let adjusted_percent = (percent - repel) / thresh_delta;
                        let q = (0.5 - (adjusted_percent * PI * 2.0).cos() * 0.5 + 0.5) * 100.9;

                        // normalize vel2 and multiply by factor
                        let vel2_length = body.velocity2.length();
                        let vel2 = (body.velocity2 / vel2_length) * q;

                        // normalize own velocity
                        let vel_length = prev.velocity.length();
                        let vel = (prev.velocity / vel_length) * q;

                        diff += vel2;
                        diff2 += vel;
                    }

                    if dist_sqrd > attract { // attract
                        let thresh_delta2 = 1.0 - attract;
                        let adjusted_percent2 = (percent - attract) / thresh_delta2;
                        let c = (1.0 - ((adjusted_percent2 * PI * 2.0).cos() * 0.5 + 0.5)) * attract_power;

                        // normalize the distance vector
                        let d = (r / length) * c;

                        diff += d;
                        diff2 -= d;
                    }
                }

                (diff, diff2)
            });

    acc += diff;
    acc2 += diff2;

    // Speed limits
    if time > 500.0 {
        let acc_squared = acc.length2();
        if acc_squared > speed_limit {
            acc *= 0.015;
        }

        let acc_squared2 = acc2.length2();
        if acc_squared2 > speed_limit {
            acc2 *= 0.015;
        }
    }

    let mut new = prev.velocity + acc;
    let mut new2 = prev.velocity2 + acc2;

    if time < 500.0 {
        let acs = new2.length2();
        if acs > speed_limit {
            new2 *= 0.15;
        }

        let acs2 = new.length2();
        if acs2 > speed_limit {
            new *= 0.15;
        }
    }

    (new, new2)
}

/// Compute next velocity of `prev`
fn next_velocity_par(time: usize, prev: &Body, bodies: &[Body])
                     -> (Vector3<f64>, Vector3<f64>) {
    let time = time as f64;
    let center = Point3 {
        x: (time / 22.0).cos() * -4200.0,
        y: (time / 14.0).sin() * 9200.0,
        z: (time / 27.0).sin() * 6000.0,
    };

    // pull to center
    let max_distance = 3400.0;
    let pull_strength = 0.042;

    // zones
    let zone = 400.0;
    let repel = 100.0;
    let align = 300.0;
    let attract = 100.0;

    let (speed_limit, attract_power);
    if time < 500.0 {
        speed_limit = 2000.0;
        attract_power = 100.9;
    } else {
        speed_limit = 0.2;
        attract_power = 20.9;
    }

    let zone_sqrd = 3.0 * (zone * zone);

    let mut acc = Vector3::zero();
    let mut acc2 = Vector3::zero();

    let dir_to_center = center - prev.position;
    let dist_to_center = dir_to_center.length();

    // orient to center
    if dist_to_center > max_distance {
        let velc = if time < 200.0 {
            0.2
        } else {
            (dist_to_center - max_distance) * pull_strength
        };

        let diff = (dir_to_center / dist_to_center) * velc;
        acc += diff;
    }

    let (diff, diff2) =
        bodies.par_iter()
              .map(|body| {
                  let r = body.position - prev.position;

                  let mut diff = Vector3::zero();
                  let mut diff2 = Vector3::zero();

                  // make sure we are not testing the particle against its own position
                  let are_same = r == Vector3::zero();

                  let dist_sqrd = r.length2();

                  if dist_sqrd < zone_sqrd && !are_same {
                      let length = dist_sqrd.sqrt();
                      let percent = dist_sqrd / zone_sqrd;

                      if dist_sqrd < repel {
                          let f = (repel / percent - 1.0) * 0.025;
                          let normal = (r / length) * f;
                          diff += normal;
                          diff2 += normal;
                      } else if dist_sqrd < align {
                          let thresh_delta = align - repel;
                          let adjusted_percent = (percent - repel) / thresh_delta;
                          let q = (0.5 - (adjusted_percent * PI * 2.0).cos() * 0.5 + 0.5) * 100.9;

                          // normalize vel2 and multiply by factor
                          let vel2_length = body.velocity2.length();
                          let vel2 = (body.velocity2 / vel2_length) * q;

                          // normalize own velocity
                          let vel_length = prev.velocity.length();
                          let vel = (prev.velocity / vel_length) * q;

                          diff += vel2;
                          diff2 += vel;
                      }

                      if dist_sqrd > attract { // attract
                          let thresh_delta2 = 1.0 - attract;
                          let adjusted_percent2 = (percent - attract) / thresh_delta2;
                          let c = (1.0 - ((adjusted_percent2 * PI * 2.0).cos() * 0.5 + 0.5)) * attract_power;

                          // normalize the distance vector
                          let d = (r / length) * c;

                          diff += d;
                          diff2 -= d;
                      }
                  }

                  (diff, diff2)
              })
              .weight(NEG_INFINITY)
              .reduce_with_identity(
                  (Vector3::zero(), Vector3::zero()),
                  |(diffa, diff2a), (diffb, diff2b)| (diffa + diffb, diff2a + diff2b));

    acc += diff;
    acc2 += diff2;

    // Speed limits
    if time > 500.0 {
        let acc_squared = acc.length2();
        if acc_squared > speed_limit {
            acc *= 0.015;
        }

        let acc_squared2 = acc2.length2();
        if acc_squared2 > speed_limit {
            acc2 *= 0.015;
        }
    }

    let mut new = prev.velocity + acc;
    let mut new2 = prev.velocity2 + acc2;

    if time < 500.0 {
        let acs = new2.length2();
        if acs > speed_limit {
            new2 *= 0.15;
        }

        let acs2 = new.length2();
        if acs2 > speed_limit {
            new *= 0.15;
        }
    }

    (new, new2)
}
<|endoftext|>


<commit_before>use ::quote::Tokens;
use ::syn::Ident;
use ::yaml_rust::Yaml;

use infer::auth;
use infer::datatype;
use infer::path;
use infer::TokensResult;

type FieldsSupport = (Vec<Tokens>, Vec<Tokens>);

fn infer_ref_obj(schema: &Yaml, required: &Vec<Yaml>) -> FieldsSupport {
    let mut fields: Vec<Tokens> = Vec::new();
    let mut additional_types: Vec<Tokens> = Vec::new();

    for (field, schema) in schema["properties"].as_hash()
        .expect("Properties must be a map.")
    {
        let field_name = field.as_str()
            .expect("Property must be a string.");
        let field_ident = Ident::new(field_name);
        let (ty, maybe_at) = datatype::infer_v3(&schema).unwrap();
        let mandate: Tokens;

        if let Some(true) = schema["required"].as_bool() {
            mandate = quote!(::tapioca::datatype::Required);
        } else if required.contains(field) {
            mandate = quote!(::tapioca::datatype::Required);
        } else {
            mandate = quote!(::tapioca::datatype::Optional);
        }

        fields.push(quote!{ #field_ident: #mandate<#ty> });

        if let Some(additional_type) = maybe_at {
            additional_types.push(additional_type);
        }
    }

    (fields, additional_types)
}

fn infer_ref(ident: &Ident, schema: &Yaml, required: &Vec<Yaml>) -> TokensResult {
    match schema["properties"].as_hash() {
        Some(_) => {
            let (fields, additionals) = infer_ref_obj(&schema, &required);

            Ok(quote! {
                #(#additionals)*

                #[derive(Debug, Deserialize, PartialEq, Serialize)]
                pub struct #ident {
                    #(pub #fields),*
                }
            })
        },
        None => {
            let (alias_to, maybe_at) = datatype::infer_v3(&schema)?;
            let additional_type = match maybe_at {
                Some(at) => at,
                None => quote!(),
            };

            Ok(quote! {
                #additional_type

                #[allow(dead_code)]
                pub type #ident = #alias_to;
            })
        },
    }
}

pub(super) fn infer_v3(schema: &Yaml) -> TokensResult {
    let paths = schema["paths"].clone();
    let path_impls: Vec<Tokens> = paths.as_hash()
        .expect("Paths must be a map.")
        .iter()
        .map(|(path, path_schema)| path::infer_v3(
            path.as_str().expect("Path must be a string."), &path_schema
        ).unwrap())
        .collect();

    let api_url = schema["servers"][0]["url"].as_str()
        .expect("Must have at least one server URL.");

    let mut schema_ref_defs: Vec<Tokens> = Vec::new();
    let schema_refs = &schema["components"]["schemas"];

    if !schema_refs.is_badvalue() {
        for (schema_ref, schema) in schema_refs.as_hash()
            .expect("#/components/schemas must be a map.")
        {
            let schema_ref_name = schema_ref.as_str()
                .expect("$ref name must be a string.");
            schema_ref_defs.push(infer_ref(
                    &Ident::new(schema_ref_name),
                    &schema,
                    &schema["required"].as_vec().unwrap_or(&Vec::new())
            )?);
        }
    }

    let mut auth_scheme_defs: Vec<Tokens> = Vec::new();
    let auth_schemes = &schema["components"]["securitySchemes"];

    if !auth_schemes.is_badvalue() {
        for (auth_scheme, schema) in auth_schemes.as_hash()
            .expect("#/components/securitySchemes must be a map.")
        {
            let auth_scheme_name = auth_scheme.as_str()
                .expect("security scheme name must be a string");

            auth_scheme_defs.push(auth::infer_v3_component(auth_scheme_name, &schema)?);
        }
    }

    let server_auth_impl: Tokens;
    let auth_struct = Ident::new("ServerAuth");
    let security_reqs = &schema["security"];

    if !security_reqs.is_badvalue() {
        server_auth_impl = auth::infer_v3(&auth_struct, &security_reqs)?
    } else {
        server_auth_impl = quote!{
            #[derive(Clone, Copy, Debug)]
            pub struct #auth_struct(());

            impl #auth_struct {
                pub fn new() -> Self {
                    Self { 0: () }
                }
            }

            impl header::Header for #auth_struct {
                fn header_name() -> &'static str {
                    ""
                }

                fn parse_header(_: &[Vec<u8>]) -> HeaderResult<Self> {
                    Ok(Self::new())
                }
            }

            impl header::HeaderFormat for #auth_struct {
                fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
                    f.write_str("")
                }
            }
        }
    }

    Ok(quote! {
        pub mod schema_ref {
            #[allow(unused_imports)]
            use super::schema_ref;

            #(#schema_ref_defs)*
        }

        pub mod auth_scheme {
            #(#auth_scheme_defs)*
        }

        use std::fmt;
        use ::tapioca::header;
        use ::tapioca::HeaderResult;

        const API_URL: &'static str = #api_url;

        #[allow(dead_code)]
        #server_auth_impl

        #(#path_impls)*
    })
}
<commit_msg>Use placeholder for valid header when no auth<commit_after>use ::quote::Tokens;
use ::syn::Ident;
use ::yaml_rust::Yaml;

use infer::auth;
use infer::datatype;
use infer::path;
use infer::TokensResult;

type FieldsSupport = (Vec<Tokens>, Vec<Tokens>);

fn infer_ref_obj(schema: &Yaml, required: &Vec<Yaml>) -> FieldsSupport {
    let mut fields: Vec<Tokens> = Vec::new();
    let mut additional_types: Vec<Tokens> = Vec::new();

    for (field, schema) in schema["properties"].as_hash()
        .expect("Properties must be a map.")
    {
        let field_name = field.as_str()
            .expect("Property must be a string.");
        let field_ident = Ident::new(field_name);
        let (ty, maybe_at) = datatype::infer_v3(&schema).unwrap();
        let mandate: Tokens;

        if let Some(true) = schema["required"].as_bool() {
            mandate = quote!(::tapioca::datatype::Required);
        } else if required.contains(field) {
            mandate = quote!(::tapioca::datatype::Required);
        } else {
            mandate = quote!(::tapioca::datatype::Optional);
        }

        fields.push(quote!{ #field_ident: #mandate<#ty> });

        if let Some(additional_type) = maybe_at {
            additional_types.push(additional_type);
        }
    }

    (fields, additional_types)
}

fn infer_ref(ident: &Ident, schema: &Yaml, required: &Vec<Yaml>) -> TokensResult {
    match schema["properties"].as_hash() {
        Some(_) => {
            let (fields, additionals) = infer_ref_obj(&schema, &required);

            Ok(quote! {
                #(#additionals)*

                #[derive(Debug, Deserialize, PartialEq, Serialize)]
                pub struct #ident {
                    #(pub #fields),*
                }
            })
        },
        None => {
            let (alias_to, maybe_at) = datatype::infer_v3(&schema)?;
            let additional_type = match maybe_at {
                Some(at) => at,
                None => quote!(),
            };

            Ok(quote! {
                #additional_type

                #[allow(dead_code)]
                pub type #ident = #alias_to;
            })
        },
    }
}

pub(super) fn infer_v3(schema: &Yaml) -> TokensResult {
    let paths = schema["paths"].clone();
    let path_impls: Vec<Tokens> = paths.as_hash()
        .expect("Paths must be a map.")
        .iter()
        .map(|(path, path_schema)| path::infer_v3(
            path.as_str().expect("Path must be a string."), &path_schema
        ).unwrap())
        .collect();

    let api_url = schema["servers"][0]["url"].as_str()
        .expect("Must have at least one server URL.");

    let mut schema_ref_defs: Vec<Tokens> = Vec::new();
    let schema_refs = &schema["components"]["schemas"];

    if !schema_refs.is_badvalue() {
        for (schema_ref, schema) in schema_refs.as_hash()
            .expect("#/components/schemas must be a map.")
        {
            let schema_ref_name = schema_ref.as_str()
                .expect("$ref name must be a string.");
            schema_ref_defs.push(infer_ref(
                    &Ident::new(schema_ref_name),
                    &schema,
                    &schema["required"].as_vec().unwrap_or(&Vec::new())
            )?);
        }
    }

    let mut auth_scheme_defs: Vec<Tokens> = Vec::new();
    let auth_schemes = &schema["components"]["securitySchemes"];

    if !auth_schemes.is_badvalue() {
        for (auth_scheme, schema) in auth_schemes.as_hash()
            .expect("#/components/securitySchemes must be a map.")
        {
            let auth_scheme_name = auth_scheme.as_str()
                .expect("security scheme name must be a string");

            auth_scheme_defs.push(auth::infer_v3_component(auth_scheme_name, &schema)?);
        }
    }

    let server_auth_impl: Tokens;
    let auth_struct = Ident::new("ServerAuth");
    let security_reqs = &schema["security"];

    if !security_reqs.is_badvalue() {
        server_auth_impl = auth::infer_v3(&auth_struct, &security_reqs)?
    } else {
        server_auth_impl = quote!{
            #[derive(Clone, Copy, Debug)]
            pub struct #auth_struct(());

            impl #auth_struct {
                pub fn new() -> Self {
                    Self { 0: () }
                }
            }

            impl header::Header for #auth_struct {
                fn header_name() -> &'static str {
                    "X-No-Auth"
                }

                fn parse_header(_: &[Vec<u8>]) -> HeaderResult<Self> {
                    Ok(Self::new())
                }
            }

            impl header::HeaderFormat for #auth_struct {
                fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
                    f.write_str("")
                }
            }
        }
    }

    Ok(quote! {
        pub mod schema_ref {
            #[allow(unused_imports)]
            use super::schema_ref;

            #(#schema_ref_defs)*
        }

        pub mod auth_scheme {
            #(#auth_scheme_defs)*
        }

        use std::fmt;
        use ::tapioca::header;
        use ::tapioca::HeaderResult;

        const API_URL: &'static str = #api_url;

        #[allow(dead_code)]
        #server_auth_impl

        #(#path_impls)*
    })
}
<|endoftext|>


<commit_before>//  Copyright (C) 2020 Éloïs SANCHEZ.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

use crate::*;
use duniter_dbs::{
    databases::bc_v1::{BcV1Db, BcV1DbReadable},
    kv_typed::prelude::Backend,
};
use fast_threadpool::{ThreadPool, ThreadPoolConfig};
use once_cell::sync::OnceCell;
use std::{
    io::BufWriter,
    path::{Path, PathBuf},
};
use termprogress::prelude::*;

static OUTPUT_DIR: OnceCell<PathBuf> = OnceCell::new();

pub(crate) fn export_bc<B: Backend>(
    bc_v1: BcV1Db<B>,
    chunk_size: usize,
    output_dir: PathBuf,
    pretty: bool,
) -> anyhow::Result<()> {
    if !output_dir.exists() {
        std::fs::create_dir_all(output_dir.clone())?;
    }
    let output_dir: &'static Path = OUTPUT_DIR.get_or_init(|| output_dir).as_path();

    if let Some(last_block) = bc_v1
        .main_blocks()
        .iter_rev(.., |it| it.keys().next_res())?
    {
        let mut chunks_count = (last_block.0).0 as usize / chunk_size;
        if (last_block.0).0 as usize % chunk_size > 0 {
            chunks_count += 1;
        }
        let chunks_count = chunks_count as f64;
        let mut progress_bar = Bar::default();

        let start_time = Instant::now();

        let (s, r) = flume::unbounded();
        let reader_handle = std::thread::spawn(move || {
            bc_v1.main_blocks().iter(.., |it| {
                it.values()
                    .map(|block_res| s.send(block_res).map_err(|_| anyhow!("fail to send")))
                    .collect::<anyhow::Result<()>>()
            })
        });

        let (s2, r2) = flume::unbounded();
        let jsonifier_handle = std::thread::spawn(move || {
            r.iter()
                .map(|block_res| {
                    let json_block_res = match block_res {
                        Ok(block) => {
                            serde_json::to_value(&block).map_err(|e| KvError::DeserError(e.into()))
                        }
                        Err(e) => Err(e),
                    };
                    s2.send(json_block_res).map_err(|_| anyhow!("fail to send"))
                })
                .collect::<anyhow::Result<()>>()
        });

        let threadpool = ThreadPool::start(ThreadPoolConfig::default(), ()).into_sync_handler();

        let mut chunk_index = 0;
        let mut json_blocks = Vec::with_capacity(chunk_size);
        let mut writers_handle = Vec::with_capacity(500_000 / chunk_size);
        r2.into_iter()
            .try_for_each::<_, anyhow::Result<()>>(|json_block_res| {
                let json_block = json_block_res?;
                json_blocks.push(json_block);
                if json_blocks.len() == chunk_size {
                    let chunk = std::mem::take(&mut json_blocks);
                    json_blocks.reserve_exact(chunk_size);
                    // Write chunk "asynchronously"
                    writers_handle
                        .push(threadpool.launch(move |_| {
                            write_chunk(chunk_index, chunk, output_dir, pretty)
                        })?);
                    chunk_index += 1;
                    if chunk_index % 8 == 0 {
                        progress_bar.set_progress(chunk_index as f64 / chunks_count);
                    }
                }
                Ok(())
            })?;
        // Write last chunk
        write_chunk(chunk_index, json_blocks, output_dir, pretty)?;
        progress_bar.set_progress(1.0);

        reader_handle
            .join()
            .map_err(|_| anyhow!("reader panic"))??;
        jsonifier_handle
            .join()
            .map_err(|_| anyhow!("jsonnifier panic"))??;
        for writer_handle in writers_handle {
            writer_handle.join()??;
        }

        progress_bar.complete();

        let duration = start_time.elapsed();
        println!(
            "Blockchain successfully exported in {}.{} seconds.",
            duration.as_secs(),
            duration.subsec_millis()
        );
        Ok(())
    } else {
        Err(anyhow!("no blockchain"))
    }
}

fn write_chunk(
    chunk_index: usize,
    chunk: Vec<serde_json::Value>,
    output_dir: &'static Path,
    pretty: bool,
) -> anyhow::Result<()> {
    let file =
        File::create(output_dir.join(format!("chunk_{}-{}.json", chunk_index, chunk.len())))?;

    let mut buffer = BufWriter::new(file);
    if pretty {
        serde_json::to_writer_pretty(&mut buffer, &serde_json::Value::Array(chunk))?;
    } else {
        serde_json::to_writer(&mut buffer, &serde_json::Value::Array(chunk))?;
    }
    buffer.flush()?;

    Ok(())
}
<commit_msg>[fix] dex: do not write last chunk if its empty<commit_after>//  Copyright (C) 2020 Éloïs SANCHEZ.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

use crate::*;
use duniter_dbs::{
    databases::bc_v1::{BcV1Db, BcV1DbReadable},
    kv_typed::prelude::Backend,
};
use fast_threadpool::{ThreadPool, ThreadPoolConfig};
use once_cell::sync::OnceCell;
use std::{
    io::BufWriter,
    path::{Path, PathBuf},
};
use termprogress::prelude::*;

static OUTPUT_DIR: OnceCell<PathBuf> = OnceCell::new();

pub(crate) fn export_bc<B: Backend>(
    bc_v1: BcV1Db<B>,
    chunk_size: usize,
    output_dir: PathBuf,
    pretty: bool,
) -> anyhow::Result<()> {
    if !output_dir.exists() {
        std::fs::create_dir_all(output_dir.clone())?;
    }
    let output_dir: &'static Path = OUTPUT_DIR.get_or_init(|| output_dir).as_path();

    if let Some(last_block) = bc_v1
        .main_blocks()
        .iter_rev(.., |it| it.keys().next_res())?
    {
        let mut chunks_count = (last_block.0).0 as usize / chunk_size;
        if (last_block.0).0 as usize % chunk_size > 0 {
            chunks_count += 1;
        }
        let chunks_count = chunks_count as f64;
        let mut progress_bar = Bar::default();

        let start_time = Instant::now();

        let (s, r) = flume::unbounded();
        let reader_handle = std::thread::spawn(move || {
            bc_v1.main_blocks().iter(.., |it| {
                it.values()
                    .map(|block_res| s.send(block_res).map_err(|_| anyhow!("fail to send")))
                    .collect::<anyhow::Result<()>>()
            })
        });

        let (s2, r2) = flume::unbounded();
        let jsonifier_handle = std::thread::spawn(move || {
            r.iter()
                .map(|block_res| {
                    let json_block_res = match block_res {
                        Ok(block) => {
                            serde_json::to_value(&block).map_err(|e| KvError::DeserError(e.into()))
                        }
                        Err(e) => Err(e),
                    };
                    s2.send(json_block_res).map_err(|_| anyhow!("fail to send"))
                })
                .collect::<anyhow::Result<()>>()
        });

        let threadpool = ThreadPool::start(ThreadPoolConfig::default(), ()).into_sync_handler();

        let mut chunk_index = 0;
        let mut json_blocks = Vec::with_capacity(chunk_size);
        let mut writers_handle = Vec::with_capacity(500_000 / chunk_size);
        r2.into_iter()
            .try_for_each::<_, anyhow::Result<()>>(|json_block_res| {
                let json_block = json_block_res?;
                json_blocks.push(json_block);
                if json_blocks.len() == chunk_size {
                    let chunk = std::mem::take(&mut json_blocks);
                    json_blocks.reserve_exact(chunk_size);
                    // Write chunk "asynchronously"
                    writers_handle
                        .push(threadpool.launch(move |_| {
                            write_chunk(chunk_index, chunk, output_dir, pretty)
                        })?);
                    chunk_index += 1;
                    if chunk_index % 8 == 0 {
                        progress_bar.set_progress(chunk_index as f64 / chunks_count);
                    }
                }
                Ok(())
            })?;
        // Write last chunk
        if !json_blocks.is_empty() {
            write_chunk(chunk_index, json_blocks, output_dir, pretty)?;
        }
        progress_bar.set_progress(1.0);

        reader_handle
            .join()
            .map_err(|_| anyhow!("reader panic"))??;
        jsonifier_handle
            .join()
            .map_err(|_| anyhow!("jsonnifier panic"))??;
        for writer_handle in writers_handle {
            writer_handle.join()??;
        }

        progress_bar.complete();

        let duration = start_time.elapsed();
        println!(
            "Blockchain successfully exported in {}.{} seconds.",
            duration.as_secs(),
            duration.subsec_millis()
        );
        Ok(())
    } else {
        Err(anyhow!("no blockchain"))
    }
}

fn write_chunk(
    chunk_index: usize,
    chunk: Vec<serde_json::Value>,
    output_dir: &'static Path,
    pretty: bool,
) -> anyhow::Result<()> {
    let file =
        File::create(output_dir.join(format!("chunk_{}-{}.json", chunk_index, chunk.len())))?;

    let mut buffer = BufWriter::new(file);
    if pretty {
        serde_json::to_writer_pretty(&mut buffer, &serde_json::Value::Array(chunk))?;
    } else {
        serde_json::to_writer(&mut buffer, &serde_json::Value::Array(chunk))?;
    }
    buffer.flush()?;

    Ok(())
}
<|endoftext|>


<commit_before><commit_msg>reorder variables declaration, add comments<commit_after><|endoftext|>


<commit_before>// CarbonReporter sends a message to a carbon end point at a regular basis.
use registry::{Registry, StdRegistry};
use std::time::Duration;
use std::thread;
use std::sync::Arc;
use reporter::base::Reporter;
use metrics::counter::StdCounter;
use metrics::gauge::StdGauge;
use metrics::meter::MeterSnapshot;
use histogram::Histogram;
use time;
use time::Timespec;
use std::net::TcpStream;
use std::io::Write;
use std::io::Error;

struct CarbonStream {
    graphite_stream: Option<TcpStream>,
    host_and_port: String,
}

// TODO perhaps we autodiscover the host and port
//
pub struct CarbonReporter {
    host_and_port: String,
    prefix: &'static str,
    registry: Arc<StdRegistry<'static>>,
    reporter_name: &'static str,
}

impl CarbonStream {
    pub fn new(host_and_port: String) -> CarbonStream {
        CarbonStream {
            host_and_port: host_and_port,
            graphite_stream: None,
        }
    }

    pub fn connect(&mut self) -> Result<String, Error> {
        let graphite_stream = try!(TcpStream::connect(&*self.host_and_port));
        self.graphite_stream = Some(graphite_stream);
        Ok(String::from(""))
    }

    pub fn write(&mut self, metric_path: String, value: String, timespec: Timespec) -> Result<String, Error> {
        let seconds_in_ms = (timespec.sec * 1000) as u32;
        let nseconds_in_ms = (timespec.nsec / 1000) as u32;
        let timestamp = seconds_in_ms + nseconds_in_ms;
        match self.graphite_stream {
            Some(ref mut stream) => {
                let carbon_command = format!("{} {} {}\n", metric_path, value, timestamp)
                    .into_bytes();
                try!(stream.write_all(&carbon_command));
            }
            None => {
                try!(self.reconnect_stream());
                try!(self.write(metric_path, value, timespec));
            }
        }
        Ok(String::from(""))
    }
    fn reconnect_stream(&mut self) -> Result<String, Error> {
        // TODO 123 is made up
        println!("Waiting 123ms and then reconnecting");
        thread::sleep(Duration::from_millis(123));
        self.connect()
    }
}

impl Reporter for CarbonReporter {
    fn get_unique_reporter_name(&self) -> &'static str {
        self.reporter_name
    }
}

fn prefix(metric_line: String, prefix_str: &'static str) -> String {
    format!("{}.{}", prefix_str, metric_line)
}

fn send_meter_metric(metric_name: &str,
                     meter: MeterSnapshot,
                     carbon: &mut CarbonStream,
                     prefix_str: &'static str,
                     ts: Timespec) -> Result<String, Error> {

    let count = meter.count.to_string();
    let m1_rate = meter.rates[0].to_string();
    let m5_rate = meter.rates[1].to_string();
    let m15_rate = meter.rates[2].to_string();
    let mean_rate = meter.mean.to_string();
    try!(carbon.write(prefix(format!("{}.count", metric_name), prefix_str),
                 count,
                 ts));
    try!(carbon.write(prefix(format!("{}.m1", metric_name), prefix_str),
                 m1_rate,
                 ts));
    try!(carbon.write(prefix(format!("{}.m5", metric_name), prefix_str),
                 m5_rate,
                 ts));
    try!(carbon.write(prefix(format!("{}.m15", metric_name), prefix_str),
                 m15_rate,
                 ts));
    try!(carbon.write(prefix(format!("{}.mean", metric_name), prefix_str),
                 mean_rate,
                 ts));
    Ok(String::from(""))
}

fn send_gauge_metric(metric_name: &str,
                     gauge: StdGauge,
                     carbon: &mut CarbonStream,
                     prefix_str: &'static str,
                     ts: Timespec) -> Result<String, Error> {
    try!(carbon.write(prefix(format!("{}", metric_name), prefix_str),
                 gauge.value.to_string(),
                 ts));
    Ok(String::from(""))
}

fn send_counter_metric(metric_name: &str,
                       counter: StdCounter,
                       carbon: &mut CarbonStream,
                       prefix_str: &'static str,
                       ts: Timespec) -> Result<String, Error> {
    try!(carbon.write(prefix(format!("{}", metric_name), prefix_str),
                 counter.value.to_string(),
                 ts));
    Ok(String::from(""))
}
fn send_histogram_metric(metric_name: &str,
                         histogram: &mut Histogram,
                         carbon: &mut CarbonStream,
                         prefix_str: &'static str,
                         ts: Timespec) -> Result<String, Error> {
    let count = histogram.count();
    // let sum = histogram.sum();
    // let mean = sum / count;
    let max = histogram.percentile(100.0).unwrap();
    let min = histogram.percentile(0.0).unwrap();

    let p50 = histogram.percentile(50.0).unwrap();
    let p75 = histogram.percentile(75.0).unwrap();
    let p95 = histogram.percentile(95.0).unwrap();
    let p98 = histogram.percentile(98.0).unwrap();
    let p99 = histogram.percentile(99.0).unwrap();
    let p999 = histogram.percentile(99.9).unwrap();
    let p9999 = histogram.percentile(99.99).unwrap();
    let p99999 = histogram.percentile(99.999).unwrap();

    try!(carbon.write(prefix(format!("{}.count", metric_name), prefix_str),
                 count.to_string(),
                 ts));

    try!(carbon.write(prefix(format!("{}.max", metric_name), prefix_str),
                 max.to_string(),
                 ts));

    // carbon
    // .write(prefix(format!("{}.mean", metric_name), prefix_str),
    // mean.into_string(),
    // ts);

    try!(carbon.write(prefix(format!("{}.min", metric_name), prefix_str),
                 min.to_string(),
                 ts));

    try!(carbon.write(prefix(format!("{}.p50", metric_name), prefix_str),
                 p50.to_string(),
                 ts));

    try!(carbon.write(prefix(format!("{}.p75", metric_name), prefix_str),
                 p75.to_string(),
                 ts));

    try!(carbon.write(prefix(format!("{}.p95", metric_name), prefix_str),
                 p95.to_string(),
                 ts));

    try!(carbon.write(prefix(format!("{}.p98", metric_name), prefix_str),
                 p98.to_string(),
                 ts));

    try!(carbon.write(prefix(format!("{}.p99", metric_name), prefix_str),
                 p99.to_string(),
                 ts));

    try!(carbon.write(prefix(format!("{}.p999", metric_name), prefix_str),
                 p999.to_string(),
                 ts));

    try!(carbon.write(prefix(format!("{}.p9999", metric_name), prefix_str),
                 p9999.to_string(),
                 ts));

    try!(carbon.write(prefix(format!("{}.p99999", metric_name), prefix_str),
                 p99999.to_string(),
                 ts));
    Ok(String::from(""))
}

impl CarbonReporter {
    pub fn new(registry: Arc<StdRegistry<'static>>,
               reporter_name: &'static str,
               host_and_port: String,
               prefix: &'static str)
               -> CarbonReporter {
        CarbonReporter {
            host_and_port: host_and_port,
            prefix: prefix,
            registry: registry,
            reporter_name: reporter_name,
        }
    }

    fn report_to_carbon_continuously(self, delay_ms: u32)
        -> thread::JoinHandle<Result<String, Error>> {
        use metrics::metric::MetricValue::{Counter, Gauge, Histogram, Meter};

        let prefix = self.prefix;
        let host_and_port = self.host_and_port.clone();
        let mut carbon = CarbonStream::new(host_and_port);
        let registry = self.registry.clone();
        thread::spawn(move || {
            loop {
                let ts = time::now().to_timespec();
                for metric_name in &registry.get_metrics_names() {
                    let metric = registry.get(metric_name);
                    try!(match metric.export_metric() {
                        Meter(x) => {
                            send_meter_metric(metric_name, x, &mut carbon, prefix, ts)
                        }
                        Gauge(x) => {
                            send_gauge_metric(metric_name, x, &mut carbon, prefix, ts)
                        }
                        Counter(x) => {
                            send_counter_metric(metric_name, x, &mut carbon, prefix, ts)
                        }
                        Histogram(mut x) => {
                            send_histogram_metric(metric_name, &mut x, &mut carbon, prefix, ts)
                        }
                    });
                }
                thread::sleep(Duration::from_millis(delay_ms as u64));
            }
        })
    }

    pub fn start(self, delay_ms: u32) {
        self.report_to_carbon_continuously(delay_ms);
    }
}

#[cfg(test)]
mod test {
    use metrics::meter::{Meter, StdMeter};
    use metrics::counter::{Counter, StdCounter};
    use metrics::gauge::{Gauge, StdGauge};
    use registry::{Registry, StdRegistry};
    use reporter::carbon::CarbonReporter;
    use std::sync::Arc;
    use std::thread;
    use histogram::*;

    #[test]
    fn meter() {
        let m = StdMeter::new();
        m.mark(100);

        let mut c: StdCounter = StdCounter::new();
        c.inc();

        let mut g: StdGauge = StdGauge { value: 0f64 };
        g.set(1.2);

        let mut hc = HistogramConfig::new();
        hc.max_value(100).precision(1);
        let mut h = Histogram::configured(hc).unwrap();

        h.record(1, 1);

        let mut r = StdRegistry::new();
        r.insert("meter1", m);
        r.insert("counter1", c);
        r.insert("gauge1", g);
        r.insert("histogram", h);

        let arc_registry = Arc::new(r);
        CarbonReporter::new(arc_registry.clone(),
                            "test",
                            "localhost:0".to_string(),
                            "asd.asdf");
    }
}
<commit_msg>Reformat<commit_after>// CarbonReporter sends a message to a carbon end point at a regular basis.
use registry::{Registry, StdRegistry};
use std::time::Duration;
use std::thread;
use std::sync::Arc;
use reporter::base::Reporter;
use metrics::counter::StdCounter;
use metrics::gauge::StdGauge;
use metrics::meter::MeterSnapshot;
use histogram::Histogram;
use time;
use time::Timespec;
use std::net::TcpStream;
use std::io::Write;
use std::io::Error;

struct CarbonStream {
    graphite_stream: Option<TcpStream>,
    host_and_port: String,
}

// TODO perhaps we autodiscover the host and port
//
pub struct CarbonReporter {
    host_and_port: String,
    prefix: &'static str,
    registry: Arc<StdRegistry<'static>>,
    reporter_name: &'static str,
}

impl CarbonStream {
    pub fn new(host_and_port: String) -> CarbonStream {
        CarbonStream {
            host_and_port: host_and_port,
            graphite_stream: None,
        }
    }

    pub fn connect(&mut self) -> Result<String, Error> {
        let graphite_stream = try!(TcpStream::connect(&*self.host_and_port));
        self.graphite_stream = Some(graphite_stream);
        Ok(String::from(""))
    }

    pub fn write(&mut self,
                 metric_path: String,
                 value: String,
                 timespec: Timespec)
                 -> Result<String, Error> {
        let seconds_in_ms = (timespec.sec * 1000) as u32;
        let nseconds_in_ms = (timespec.nsec / 1000) as u32;
        let timestamp = seconds_in_ms + nseconds_in_ms;
        match self.graphite_stream {
            Some(ref mut stream) => {
                let carbon_command = format!("{} {} {}\n", metric_path, value, timestamp)
                    .into_bytes();
                try!(stream.write_all(&carbon_command));
            }
            None => {
                try!(self.reconnect_stream());
                try!(self.write(metric_path, value, timespec));
            }
        }
        Ok(String::from(""))
    }
    fn reconnect_stream(&mut self) -> Result<String, Error> {
        // TODO 123 is made up
        println!("Waiting 123ms and then reconnecting");
        thread::sleep(Duration::from_millis(123));
        self.connect()
    }
}

impl Reporter for CarbonReporter {
    fn get_unique_reporter_name(&self) -> &'static str {
        self.reporter_name
    }
}

fn prefix(metric_line: String, prefix_str: &'static str) -> String {
    format!("{}.{}", prefix_str, metric_line)
}

fn send_meter_metric(metric_name: &str,
                     meter: MeterSnapshot,
                     carbon: &mut CarbonStream,
                     prefix_str: &'static str,
                     ts: Timespec)
                     -> Result<String, Error> {

    let count = meter.count.to_string();
    let m1_rate = meter.rates[0].to_string();
    let m5_rate = meter.rates[1].to_string();
    let m15_rate = meter.rates[2].to_string();
    let mean_rate = meter.mean.to_string();
    try!(carbon.write(prefix(format!("{}.count", metric_name), prefix_str),
                      count,
                      ts));
    try!(carbon.write(prefix(format!("{}.m1", metric_name), prefix_str),
                      m1_rate,
                      ts));
    try!(carbon.write(prefix(format!("{}.m5", metric_name), prefix_str),
                      m5_rate,
                      ts));
    try!(carbon.write(prefix(format!("{}.m15", metric_name), prefix_str),
                      m15_rate,
                      ts));
    try!(carbon.write(prefix(format!("{}.mean", metric_name), prefix_str),
                      mean_rate,
                      ts));
    Ok(String::from(""))
}

fn send_gauge_metric(metric_name: &str,
                     gauge: StdGauge,
                     carbon: &mut CarbonStream,
                     prefix_str: &'static str,
                     ts: Timespec)
                     -> Result<String, Error> {
    try!(carbon.write(prefix(format!("{}", metric_name), prefix_str),
                      gauge.value.to_string(),
                      ts));
    Ok(String::from(""))
}

fn send_counter_metric(metric_name: &str,
                       counter: StdCounter,
                       carbon: &mut CarbonStream,
                       prefix_str: &'static str,
                       ts: Timespec)
                       -> Result<String, Error> {
    try!(carbon.write(prefix(format!("{}", metric_name), prefix_str),
                      counter.value.to_string(),
                      ts));
    Ok(String::from(""))
}
fn send_histogram_metric(metric_name: &str,
                         histogram: &mut Histogram,
                         carbon: &mut CarbonStream,
                         prefix_str: &'static str,
                         ts: Timespec)
                         -> Result<String, Error> {
    let count = histogram.count();
    // let sum = histogram.sum();
    // let mean = sum / count;
    let max = histogram.percentile(100.0).unwrap();
    let min = histogram.percentile(0.0).unwrap();

    let p50 = histogram.percentile(50.0).unwrap();
    let p75 = histogram.percentile(75.0).unwrap();
    let p95 = histogram.percentile(95.0).unwrap();
    let p98 = histogram.percentile(98.0).unwrap();
    let p99 = histogram.percentile(99.0).unwrap();
    let p999 = histogram.percentile(99.9).unwrap();
    let p9999 = histogram.percentile(99.99).unwrap();
    let p99999 = histogram.percentile(99.999).unwrap();

    try!(carbon.write(prefix(format!("{}.count", metric_name), prefix_str),
                      count.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.max", metric_name), prefix_str),
                      max.to_string(),
                      ts));

    // carbon
    // .write(prefix(format!("{}.mean", metric_name), prefix_str),
    // mean.into_string(),
    // ts);

    try!(carbon.write(prefix(format!("{}.min", metric_name), prefix_str),
                      min.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p50", metric_name), prefix_str),
                      p50.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p75", metric_name), prefix_str),
                      p75.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p95", metric_name), prefix_str),
                      p95.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p98", metric_name), prefix_str),
                      p98.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p99", metric_name), prefix_str),
                      p99.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p999", metric_name), prefix_str),
                      p999.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p9999", metric_name), prefix_str),
                      p9999.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p99999", metric_name), prefix_str),
                      p99999.to_string(),
                      ts));
    Ok(String::from(""))
}

impl CarbonReporter {
    pub fn new(registry: Arc<StdRegistry<'static>>,
               reporter_name: &'static str,
               host_and_port: String,
               prefix: &'static str)
               -> CarbonReporter {
        CarbonReporter {
            host_and_port: host_and_port,
            prefix: prefix,
            registry: registry,
            reporter_name: reporter_name,
        }
    }

    fn report_to_carbon_continuously(self,
                                     delay_ms: u32)
                                     -> thread::JoinHandle<Result<String, Error>> {
        use metrics::metric::MetricValue::{Counter, Gauge, Histogram, Meter};

        let prefix = self.prefix;
        let host_and_port = self.host_and_port.clone();
        let mut carbon = CarbonStream::new(host_and_port);
        let registry = self.registry.clone();
        thread::spawn(move || {
            loop {
                let ts = time::now().to_timespec();
                for metric_name in &registry.get_metrics_names() {
                    let metric = registry.get(metric_name);
                    try!(match metric.export_metric() {
                        Meter(x) => send_meter_metric(metric_name, x, &mut carbon, prefix, ts),
                        Gauge(x) => send_gauge_metric(metric_name, x, &mut carbon, prefix, ts),
                        Counter(x) => send_counter_metric(metric_name, x, &mut carbon, prefix, ts),
                        Histogram(mut x) => {
                            send_histogram_metric(metric_name, &mut x, &mut carbon, prefix, ts)
                        }
                    });
                }
                thread::sleep(Duration::from_millis(delay_ms as u64));
            }
        })
    }

    pub fn start(self, delay_ms: u32) {
        self.report_to_carbon_continuously(delay_ms);
    }
}

#[cfg(test)]
mod test {
    use metrics::meter::{Meter, StdMeter};
    use metrics::counter::{Counter, StdCounter};
    use metrics::gauge::{Gauge, StdGauge};
    use registry::{Registry, StdRegistry};
    use reporter::carbon::CarbonReporter;
    use std::sync::Arc;
    use histogram::*;

    #[test]
    fn meter() {
        let m = StdMeter::new();
        m.mark(100);

        let mut c: StdCounter = StdCounter::new();
        c.inc();

        let mut g: StdGauge = StdGauge { value: 0f64 };
        g.set(1.2);

        let mut hc = HistogramConfig::new();
        hc.max_value(100).precision(1);
        let mut h = Histogram::configured(hc).unwrap();

        h.record(1, 1);

        let mut r = StdRegistry::new();
        r.insert("meter1", m);
        r.insert("counter1", c);
        r.insert("gauge1", g);
        r.insert("histogram", h);

        let arc_registry = Arc::new(r);
        CarbonReporter::new(arc_registry.clone(),
                            "test",
                            "localhost:0".to_string(),
                            "asd.asdf");
    }
}
<|endoftext|>


<commit_before>use ncurses::*;

use std::sync::Arc;
use std::sync::RwLock;
use std::sync::mpsc::Sender;
use std::sync::Arc;
use std::sync::RwLock;
use event::Modifier;
use event::InputEvent;
use client::generic::GenericClient;
use buffer::Buffer;
use host::Host;

use host::Host;
use buffer::Buffer;

pub struct CursesHost {
    sender: Sender,
    buffers: Arc<RwLock<Vec<Buffer>>>,
}

pub impl Host for CursesHost {
    fn new(buffers: Arc<RwLock<Vec<Buffer>>>, sender: Sender) {GenericClient{sender: sender, buffers: buffers}}

    fn setup(&self) {
        initscr();
        raw();

        // Allow for extended keyboard (like F1).
        keypad(stdscr, true);
        noecho();
    }

    fn teardown(&self) {
        endwin();
    }

    fn poll(&self) {
        refresh();
        let ch = getch();
        return InputEvent {
            modifier: Modifier::NONE,
            character: char::from_u32(getch() as u32).expect("Invalid character"),
        }
    }
}
<commit_msg>Fix type signatures and implementation<commit_after>use ncurses::*;

use std::char;
use std::sync::Arc;
use std::sync::RwLock;
use std::sync::mpsc::Sender;

use host::Host;
use buffer::Buffer;
use event::Modifier;
use event::InputEvent;
use client::generic::GenericClient;

pub struct CursesHost {
    sender: Sender<InputEvent>,
    buffers: Arc<RwLock<Vec<Buffer>>>,
}

pub impl Host for CursesHost {
    fn new(buffers: Arc<RwLock<Vec<Buffer>>>, sender: Sender<InputEvent>) -> Self {CursesHost{sender: sender, buffers: buffers}}

    fn sender(&self) -> Sender<InputEvent> {self.sender}

    fn setup(&self) {
        initscr();
        raw();

        // Allow for extended keyboard (like F1).
        keypad(stdscr, true);
        noecho();
    }

    fn teardown(&self) {
        endwin();
    }

    fn poll(&self) -> InputEvent{
        refresh();
        let ch = getch();
        return InputEvent {
            modifier: Some(Modifier::NONE),
            character: char::from_u32(getch() as u32),
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;

use cmp;

pub fn borrow(num: &str, needed: char) -> Result<String, &'static str> {
    match num.rfind(|c| cmp(c, needed) != Ordering::Less) {
        Some(i) => {
            let (prefix, end) = num.split_at(i);
            let (expand_char, suffix) = end.split_at(1);
            match expand_char {
                "X" => {
                    if needed == 'I' {
                        Ok(prefix.to_string() + "VIIIII")
                    } else {
                        Ok(prefix.to_string() + "VV" + suffix)
                    }
                },
                "V" => {
                    Ok(prefix.to_string() + "IIIII")
                },
                "I" => {
                    Ok(num.into())
                },
                _ => {
                    Err("unknown digit")
                }
            }
        },
        None => {
            Err("Would be a negative number")
        }
    }
}

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

    #[test]
    fn cannot_get_something_from_nothing() {
        assert!(borrow("", 'I').is_err());
    }

    #[test]
    fn borrow_i_from_ii_returns_string_without_change() {
        assert_eq!("II", borrow("II", 'I').unwrap());
    }

    #[test]
    fn borrow_i_from_v() {
        assert_eq!("IIIII", borrow("V", 'I').unwrap());
    }

    #[test]
    fn borrow_v_from_x() {
        assert_eq!("VV", borrow("X", 'V').unwrap());
    }

    #[test]
    fn borrow_v_from_cx() {
        assert_eq!("CVV", borrow("CX", 'V').unwrap());
    }

    #[test]
    fn borrow_i_from_x_borrows_transitively() {
        assert_eq!("VIIIII", borrow("X", 'I').unwrap());
    }

    #[test]
    fn borrow_v_from_xx_only_borrows_once() {
        assert_eq!("XVV", borrow("XX", 'V').unwrap());
    }

    #[test]
    fn borrow_v_from_cxi_returns_the_tail_part_properly() {
        assert_eq!("CVVI", borrow("CXI", 'V').unwrap());
    }
}
<commit_msg>Extract expansion logic from borrow() in rust<commit_after>use std::cmp::Ordering;

use cmp;

pub fn borrow(num: &str, needed: char) -> Result<String, String> {
    match num.rfind(|c| cmp(c, needed) != Ordering::Less) {
        Some(i) => {
            let (prefix, end) = num.split_at(i);
            let (expand_char, suffix) = end.split_at(1);
            match expand_digit_to_make(expand_char.chars().next().unwrap(), needed) {
                Ok(middle) => Ok(prefix.to_string() + middle.as_ref() + suffix),
                Err(e) => Err(e),
            }
        },
        None => {
            Err("Would be a negative number".into())
        }
    }
}

fn expand_digit_to_make(original: char, needed: char) -> Result<String, String> {
    match original {
        'X' => {
            if needed == 'I' {
                Ok("VIIIII".into())
            } else {
                Ok("VV".into())
            }
        },
        'V' => {
            Ok("IIIII".into())
        },
        'I' => {
            Ok(original.to_string())
        },
        _ => {
            Err(format!("Don't know how to borrow from {}", original))
        }
    }
}

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

    #[test]
    fn cannot_get_something_from_nothing() {
        assert!(borrow("", 'I').is_err());
    }

    #[test]
    fn borrow_i_from_ii_returns_string_without_change() {
        assert_eq!("II", borrow("II", 'I').unwrap());
    }

    #[test]
    fn borrow_i_from_v() {
        assert_eq!("IIIII", borrow("V", 'I').unwrap());
    }

    #[test]
    fn borrow_v_from_x() {
        assert_eq!("VV", borrow("X", 'V').unwrap());
    }

    #[test]
    fn borrow_v_from_cx() {
        assert_eq!("CVV", borrow("CX", 'V').unwrap());
    }

    #[test]
    fn borrow_i_from_x_borrows_transitively() {
        assert_eq!("VIIIII", borrow("X", 'I').unwrap());
    }

    #[test]
    fn borrow_v_from_xx_only_borrows_once() {
        assert_eq!("XVV", borrow("XX", 'V').unwrap());
    }

    #[test]
    fn borrow_v_from_cxi_returns_the_tail_part_properly() {
        assert_eq!("CVVI", borrow("CXI", 'V').unwrap());
    }
}
<|endoftext|>


<commit_before>//! The Metal framework defines data types that are used in multiple places throughout the framework.
//!
//! Taken from https://developer.apple.com/library/ios/documentation/Metal/Reference/MetalDataTypes_Ref/index.html

use cocoa::foundation::NSUInteger;
use libc::uint32_t;

/// An RGBA value used for a color pixel.
#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
pub struct MTLClearColor {
    /// The red color channel.
    pub red: f64,

    /// The green color channel.
    pub blue: f64,

    /// The blue color channel.
    pub green: f64,

    /// The alpha color channel.
    pub alpha: f64
}

/// A location of a pixel in an image or texture, relative to the upper-left corner which is (0,0).
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLOrigin {
    /// The x coordinate of the location.
    pub x: NSUInteger,

    /// The y coordinate of the location.
    pub y: NSUInteger,

    /// The z coordinate of the location.
    pub z: NSUInteger
}

/// A rectangular block of pixels in an image or texture, defined by its upper-left corner and its size.
#[repr(C)]
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
pub struct MTLRegion {
    /// The location of the upper-left corner of the block.
    pub origin: MTLOrigin,

    /// The size of the block.
    pub size: MTLSize
}

/// A rectangle for the scissor fragment test.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLScissorRect {
    /// The x window coordinate of the upper-left corner of the scissor rectangle.
    pub x: NSUInteger,

    /// The y window coordinate of the upper-left corner of the scissor rectangle.
    pub y: NSUInteger,

    /// The width of the scissor rectangle, in pixels.
    pub width: NSUInteger,

    /// The height of the scissor rectangle, in pixels.
    pub height: NSUInteger
}

/// A set of dimensions to declare the size of an object, such as an image, texture, threadgroup, or grid.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLSize {
    /// The x dimension of the object size.
    pub width: NSUInteger,

    /// The y dimension of the object size.
    pub height: NSUInteger,

    /// The z dimension of the object size.
    pub depth: NSUInteger
}

/// A 3D rectangular region for the viewport clipping.
#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
pub struct MTLViewport {
    /// The x coordinate of the upper-left corner of the viewport.
    pub originX: f64,

    /// The y coordinate of the upper-left corner of the viewport.
    pub originY: f64,

    /// The width of the viewport, in pixels.
    pub width: f64,

    /// The height of the viewport, in pixels.
    pub height: f64,

    /// The z coordinate of the near clipping plane of the viewport.
    pub znear: f64,

    /// The z coordinate of the far clipping plane of the viewport.
    pub zfar: f64
}

/// The data layout required for drawing primitives via indirect buffer calls.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLDrawPrimitivesIndirectArguments {
    /// The number of indices to draw.
    pub vertexCount: uint32_t,

    /// The number of instances to draw.
    pub instanceCount: uint32_t,

    /// The first index to draw.
    pub vertexStart: uint32_t,

    /// The first instance to draw.
    pub baseInstance: uint32_t
}

/// The data layout required for drawing indexed primitives via indirect buffer calls.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLDrawIndexedPrimitivesIndirectArguments {
    /// For each instance, the number of indices to read from the index buffer.
    pub indexCount: uint32_t,

    /// The number of instances to draw.
    pub instanceCount: uint32_t,

    /// The first index to draw.
    pub indexStart: uint32_t,

    /// The first vertex to draw.
    pub baseVertex: uint32_t,

    /// The first instance to draw.
    pub baseInstance: uint32_t
}

/// The data layout required for dispatching threadgroups via indirect buffer calls.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLDispatchThreadgroupsIndirectArguments {
    /// The number of threadgroups for the grid, in each dimension.
    threadgroupsPerGrid: [uint32_t; 3]
}
<commit_msg>Small fixes<commit_after>//! The Metal framework defines data types that are used in multiple places throughout the framework.
//!
//! Taken from https://developer.apple.com/library/ios/documentation/Metal/Reference/MetalDataTypes_Ref/index.html

use cocoa::foundation::NSUInteger;
use libc::uint32_t;

/// An RGBA value used for a color pixel.
#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
pub struct MTLClearColor {
    /// The red color channel.
    pub red: f64,

    /// The green color channel.
    pub green: f64,

    /// The blue color channel.
    pub blue: f64,

    /// The alpha color channel.
    pub alpha: f64
}

/// A location of a pixel in an image or texture, relative to the upper-left corner which is (0,0).
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLOrigin {
    /// The x coordinate of the location.
    pub x: NSUInteger,

    /// The y coordinate of the location.
    pub y: NSUInteger,

    /// The z coordinate of the location.
    pub z: NSUInteger
}

/// A rectangular block of pixels in an image or texture, defined by its upper-left corner and its size.
#[repr(C)]
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
pub struct MTLRegion {
    /// The location of the upper-left corner of the block.
    pub origin: MTLOrigin,

    /// The size of the block.
    pub size: MTLSize
}

/// A rectangle for the scissor fragment test.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLScissorRect {
    /// The x window coordinate of the upper-left corner of the scissor rectangle.
    pub x: NSUInteger,

    /// The y window coordinate of the upper-left corner of the scissor rectangle.
    pub y: NSUInteger,

    /// The width of the scissor rectangle, in pixels.
    pub width: NSUInteger,

    /// The height of the scissor rectangle, in pixels.
    pub height: NSUInteger
}

/// A set of dimensions to declare the size of an object, such as an image, texture, threadgroup, or grid.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLSize {
    /// The x dimension of the object size.
    pub width: NSUInteger,

    /// The y dimension of the object size.
    pub height: NSUInteger,

    /// The z dimension of the object size.
    pub depth: NSUInteger
}

/// A 3D rectangular region for the viewport clipping.
#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
pub struct MTLViewport {
    /// The x coordinate of the upper-left corner of the viewport.
    pub originX: f64,

    /// The y coordinate of the upper-left corner of the viewport.
    pub originY: f64,

    /// The width of the viewport, in pixels.
    pub width: f64,

    /// The height of the viewport, in pixels.
    pub height: f64,

    /// The z coordinate of the near clipping plane of the viewport.
    pub znear: f64,

    /// The z coordinate of the far clipping plane of the viewport.
    pub zfar: f64
}

/// The data layout required for drawing primitives via indirect buffer calls.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLDrawPrimitivesIndirectArguments {
    /// The number of indices to draw.
    pub vertexCount: uint32_t,

    /// The number of instances to draw.
    pub instanceCount: uint32_t,

    /// The first index to draw.
    pub vertexStart: uint32_t,

    /// The first instance to draw.
    pub baseInstance: uint32_t
}

/// The data layout required for drawing indexed primitives via indirect buffer calls.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLDrawIndexedPrimitivesIndirectArguments {
    /// For each instance, the number of indices to read from the index buffer.
    pub indexCount: uint32_t,

    /// The number of instances to draw.
    pub instanceCount: uint32_t,

    /// The first index to draw.
    pub indexStart: uint32_t,

    /// The first vertex to draw.
    pub baseVertex: uint32_t,

    /// The first instance to draw.
    pub baseInstance: uint32_t
}

/// The data layout required for dispatching threadgroups via indirect buffer calls.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLDispatchThreadgroupsIndirectArguments {
    /// The number of threadgroups for the grid, in each dimension.
    pub threadgroupsPerGrid: [uint32_t; 3]
}
<|endoftext|>


<commit_before>//! Internal traits and functions used to implement parallel
//! iteration. These should be considered highly unstable: users of
//! parallel iterators should not need to interact with them directly.
//! See `README.md` for a high-level overview.

use join;
use super::IndexedParallelIterator;
use super::len::*;

pub trait ProducerCallback<ITEM> {
    type Output;
    fn callback<P>(self, producer: P) -> Self::Output
        where P: Producer<Item=ITEM>;
}

/// A producer which will produce a fixed number of items N. This is
/// not queryable through the API; the consumer is expected to track
/// it.
pub trait Producer: IntoIterator + Send {
    /// Cost to produce `len` items, where `len` must be `N`.
    fn cost(&mut self, len: usize) -> f64;

    /// Split into two producers; one produces items `0..index`, the
    /// other `index..N`. Index must be less than `N`.
    fn split_at(self, index: usize) -> (Self, Self);
}

/// A consumer which consumes items that are fed to it.
pub trait Consumer<Item>: Send {
    type Folder: Folder<Item, Result=Self::Result>;
    type Reducer: Reducer<Self::Result>;
    type Result: Send;

    /// If it costs `producer_cost` to produce the items we will
    /// consume, returns cost adjusted to account for consuming them.
    fn cost(&mut self, producer_cost: f64) -> f64;

    /// Divide the consumer into two consumers, one processing items
    /// `0..index` and one processing items from `index..`. Also
    /// produces a reducer that can be used to reduce the results at
    /// the end.
    fn split_at(self, index: usize) -> (Self, Self, Self::Reducer);

    /// Convert the consumer into a folder that can consume items
    /// sequentially, eventually producing a final result.
    fn into_folder(self) -> Self::Folder;

}

pub trait Folder<Item> {
    type Result;

    /// Consume next item and return new sequential state.
    fn consume(self, item: Item) -> Self;

    /// Finish consuming items, produce final result.
    fn complete(self) -> Self::Result;
}

pub trait Reducer<Result> {
    /// Reduce two final results into one; this is executed after a
    /// split.
    fn reduce(self, left: Result, right: Result) -> Result;
}

/// A stateless consumer can be freely copied.
pub trait UnindexedConsumer<ITEM>: Consumer<ITEM> {
    fn split_off(&self) -> Self;
    fn to_reducer(&self) -> Self::Reducer;
}

pub fn bridge<PAR_ITER,C>(mut par_iter: PAR_ITER,
                             consumer: C)
                             -> C::Result
    where PAR_ITER: IndexedParallelIterator, C: Consumer<PAR_ITER::Item>
{
    let len = par_iter.len();
    return par_iter.with_producer(Callback { len: len,
                                             consumer: consumer, });

    struct Callback<C> {
        len: usize,
        consumer: C,
    }

    impl<C, ITEM> ProducerCallback<ITEM> for Callback<C>
        where C: Consumer<ITEM>
    {
        type Output = C::Result;
        fn callback<P>(mut self, mut producer: P) -> C::Result
            where P: Producer<Item=ITEM>
        {
            let producer_cost = producer.cost(self.len);
            let cost = self.consumer.cost(producer_cost);
            bridge_producer_consumer(self.len, cost, producer, self.consumer)
        }
    }
}

fn bridge_producer_consumer<P,C>(len: usize,
                                 cost: f64,
                                 producer: P,
                                 consumer: C)
                                 -> C::Result
    where P: Producer, C: Consumer<P::Item>
{
    if len > 1 && cost > THRESHOLD {
        let mid = len / 2;
        let (left_producer, right_producer) = producer.split_at(mid);
        let (left_consumer, right_consumer, reducer) = consumer.split_at(mid);
        let (left_result, right_result) =
            join(|| bridge_producer_consumer(mid, cost / 2.0,
                                             left_producer, left_consumer),
                 || bridge_producer_consumer(len - mid, cost / 2.0,
                                             right_producer, right_consumer));
        reducer.reduce(left_result, right_result)
    } else {
        let mut folder = consumer.into_folder();
        for item in producer {
            folder = folder.consume(item);
        }
        folder.complete()
    }
}

/// Utility type for consumers that don't need a "reduce" step. Just
/// reduces unit to unit.
pub struct NoopReducer;

impl Reducer<()> for NoopReducer {
    fn reduce(self, _left: (), _right: ()) { }
}

<commit_msg>add Sized bounds to meet new WF requirements<commit_after>//! Internal traits and functions used to implement parallel
//! iteration. These should be considered highly unstable: users of
//! parallel iterators should not need to interact with them directly.
//! See `README.md` for a high-level overview.

use join;
use super::IndexedParallelIterator;
use super::len::*;

pub trait ProducerCallback<ITEM> {
    type Output;
    fn callback<P>(self, producer: P) -> Self::Output
        where P: Producer<Item=ITEM>;
}

/// A producer which will produce a fixed number of items N. This is
/// not queryable through the API; the consumer is expected to track
/// it.
pub trait Producer: IntoIterator + Send + Sized {
    /// Cost to produce `len` items, where `len` must be `N`.
    fn cost(&mut self, len: usize) -> f64;

    /// Split into two producers; one produces items `0..index`, the
    /// other `index..N`. Index must be less than `N`.
    fn split_at(self, index: usize) -> (Self, Self);
}

/// A consumer which consumes items that are fed to it.
pub trait Consumer<Item>: Send + Sized {
    type Folder: Folder<Item, Result=Self::Result>;
    type Reducer: Reducer<Self::Result>;
    type Result: Send;

    /// If it costs `producer_cost` to produce the items we will
    /// consume, returns cost adjusted to account for consuming them.
    fn cost(&mut self, producer_cost: f64) -> f64;

    /// Divide the consumer into two consumers, one processing items
    /// `0..index` and one processing items from `index..`. Also
    /// produces a reducer that can be used to reduce the results at
    /// the end.
    fn split_at(self, index: usize) -> (Self, Self, Self::Reducer);

    /// Convert the consumer into a folder that can consume items
    /// sequentially, eventually producing a final result.
    fn into_folder(self) -> Self::Folder;

}

pub trait Folder<Item> {
    type Result;

    /// Consume next item and return new sequential state.
    fn consume(self, item: Item) -> Self;

    /// Finish consuming items, produce final result.
    fn complete(self) -> Self::Result;
}

pub trait Reducer<Result> {
    /// Reduce two final results into one; this is executed after a
    /// split.
    fn reduce(self, left: Result, right: Result) -> Result;
}

/// A stateless consumer can be freely copied.
pub trait UnindexedConsumer<ITEM>: Consumer<ITEM> {
    fn split_off(&self) -> Self;
    fn to_reducer(&self) -> Self::Reducer;
}

pub fn bridge<PAR_ITER,C>(mut par_iter: PAR_ITER,
                             consumer: C)
                             -> C::Result
    where PAR_ITER: IndexedParallelIterator, C: Consumer<PAR_ITER::Item>
{
    let len = par_iter.len();
    return par_iter.with_producer(Callback { len: len,
                                             consumer: consumer, });

    struct Callback<C> {
        len: usize,
        consumer: C,
    }

    impl<C, ITEM> ProducerCallback<ITEM> for Callback<C>
        where C: Consumer<ITEM>
    {
        type Output = C::Result;
        fn callback<P>(mut self, mut producer: P) -> C::Result
            where P: Producer<Item=ITEM>
        {
            let producer_cost = producer.cost(self.len);
            let cost = self.consumer.cost(producer_cost);
            bridge_producer_consumer(self.len, cost, producer, self.consumer)
        }
    }
}

fn bridge_producer_consumer<P,C>(len: usize,
                                 cost: f64,
                                 producer: P,
                                 consumer: C)
                                 -> C::Result
    where P: Producer, C: Consumer<P::Item>
{
    if len > 1 && cost > THRESHOLD {
        let mid = len / 2;
        let (left_producer, right_producer) = producer.split_at(mid);
        let (left_consumer, right_consumer, reducer) = consumer.split_at(mid);
        let (left_result, right_result) =
            join(|| bridge_producer_consumer(mid, cost / 2.0,
                                             left_producer, left_consumer),
                 || bridge_producer_consumer(len - mid, cost / 2.0,
                                             right_producer, right_consumer));
        reducer.reduce(left_result, right_result)
    } else {
        let mut folder = consumer.into_folder();
        for item in producer {
            folder = folder.consume(item);
        }
        folder.complete()
    }
}

/// Utility type for consumers that don't need a "reduce" step. Just
/// reduces unit to unit.
pub struct NoopReducer;

impl Reducer<()> for NoopReducer {
    fn reduce(self, _left: (), _right: ()) { }
}
<|endoftext|>