<commit_before>use std::f64;

use deflate::calculate_block_size_auto_type;
use lz77::{Lz77Store, ZopfliBlockState};
use Options;

/// Finds minimum of function `f(i)` where `i` is of type `usize`, `f(i)` is of type
/// `f64`, `i` is in range `start-end` (excluding `end`).
/// Returns the index to the minimum and the minimum value.
fn find_minimum<F>(f: F, start: usize, end: usize) -> (usize, f64)
    where F: Fn(usize) -> f64
{
    let mut start = start;
    let mut end = end;
    if end - start < 1024 {
        let mut best = f64::MAX;
        let mut result = start;
        for i in start..end {
            let v = f(i);
            if v < best {
                best = v;
                result = i;
            }
        }
        (result, best)
    } else {
        /* Try to find minimum faster by recursively checking multiple points. */
        let num = 9;  /* Good value: 9. ?!?!?!?! */
        let mut p = vec![0; num];
        let mut vp = vec![0.0; num];
        let mut lastbest = f64::MAX;
        let mut pos = start;

        while end - start > num {
            let mut besti = 0;
            let mut best = f64::MAX;
            let multiplier = (end - start) / (num + 1);
            for i in 0..num {
                p[i] = start + (i + 1) * multiplier;
                vp[i] = f(p[i]);
                if vp[i] < best {
                    best = vp[i];
                    besti = i;
                }
            }
            if best > lastbest {
                break;
            }

            start = if besti == 0 { start } else { p[besti - 1] };
            end = if besti == num - 1 { end } else { p[besti + 1] };

            pos = p[besti];
            lastbest = best;
        }
        (pos, lastbest)
    }
}

/// Returns estimated cost of a block in bits.  It includes the size to encode the
/// tree and the size to encode all literal, length and distance symbols and their
/// extra bits.
///
/// litlens: lz77 lit/lengths
/// dists: ll77 distances
/// lstart: start of block
/// lend: end of block (not inclusive)
fn estimate_cost(lz77: &Lz77Store, lstart: usize, lend: usize) -> f64 {
    calculate_block_size_auto_type(lz77, lstart, lend)
}

/// Finds next block to try to split, the largest of the available ones.
/// The largest is chosen to make sure that if only a limited amount of blocks is
/// requested, their sizes are spread evenly.
/// lz77size: the size of the LL77 data, which is the size of the done array here.
/// done: array indicating which blocks starting at that position are no longer
///     splittable (splitting them increases rather than decreases cost).
/// splitpoints: the splitpoints found so far.
/// npoints: the amount of splitpoints found so far.
/// lstart: output variable, giving start of block.
/// lend: output variable, giving end of block.
/// returns 1 if a block was found, 0 if no block found (all are done).
fn find_largest_splittable_block(lz77size: usize, done: &[u8], splitpoints: &[usize]) -> Option<(usize, usize)> {
    let mut longest = 0;
    let mut found = None;

    let mut last = 0;

    for &item in splitpoints.iter() {
        if done[last] == 0 && item - last > longest {
            found = Some((last, item));
            longest = item - last;
        }
        last = item;
    }

    let end = lz77size - 1;
    if done[last] == 0 && end - last > longest {
        found = Some((last, end));
    }

    found
}

/// Prints the block split points as decimal and hex values in the terminal.
fn print_block_split_points(lz77: &Lz77Store, lz77splitpoints: &[usize]) {
    let nlz77points = lz77splitpoints.len();
    let mut splitpoints = Vec::with_capacity(nlz77points);

    /* The input is given as lz77 indices, but we want to see the uncompressed
    index values. */
    let mut pos = 0;
    if nlz77points > 0 {
        for (i, item) in lz77.litlens.iter().enumerate() {
            let length = item.size();
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == nlz77points {
                    break;
                }
            }
            pos += length;
        }
    }
    assert!(splitpoints.len() == nlz77points);

    println!("block split points: {} (hex: {})", splitpoints.iter().map(|&sp| format!("{}", sp)).collect::<Vec<_>>().join(" "), splitpoints.iter().map(|&sp| format!("{:x}", sp)).collect::<Vec<_>>().join(" "));
}

/// Does blocksplitting on LZ77 data.
/// The output splitpoints are indices in the LZ77 data.
/// maxblocks: set a limit to the amount of blocks. Set to 0 to mean no limit.
pub fn blocksplit_lz77(options: &Options, lz77: &Lz77Store, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    if lz77.size() < 10 {
        return;  /* This code fails on tiny files. */
    }

    let mut numblocks = 1;
    let mut done = vec![0; lz77.size()];
    let mut lstart = 0;
    let mut lend = lz77.size();

    while maxblocks != 0 && numblocks < maxblocks {
        assert!(lstart < lend);
        let find_minimum_result = find_minimum(|i|
            estimate_cost(lz77, lstart, i) + estimate_cost(lz77, i, lend), lstart + 1, lend
        );
        let llpos = find_minimum_result.0;
        let splitcost = find_minimum_result.1;

        assert!(llpos > lstart);
        assert!(llpos < lend);

        let origcost = estimate_cost(lz77, lstart, lend);

        if splitcost > origcost || llpos == lstart + 1 || llpos == lend {
            done[lstart] = 1;
        } else {
            splitpoints.push(llpos);
            splitpoints.sort();
            numblocks += 1;
        }

        // If `find_largest_splittable_block` returns `None`, no further split will
        // likely reduce compression.
        let is_finished = find_largest_splittable_block(lz77.size(), &done, splitpoints)
            .map_or(true, |(start, end)| {
                lstart = start;
                lend = end;
                lend - lstart < 10
            });

        if is_finished { break }
    }

    if options.verbose {
        print_block_split_points(lz77, splitpoints);
    }
}

/// Does blocksplitting on uncompressed data.
/// The output splitpoints are indices in the uncompressed bytes.
///
/// options: general program options.
/// in: uncompressed input data
/// instart: where to start splitting
/// inend: where to end splitting (not inclusive)
/// maxblocks: maximum amount of blocks to split into, or 0 for no limit
/// splitpoints: dynamic array to put the resulting split point coordinates into.
///   The coordinates are indices in the input array.
/// npoints: pointer to amount of splitpoints, for the dynamic array. The amount of
///   blocks is the amount of splitpoitns + 1.
pub fn blocksplit(options: &Options, in_data: &[u8], instart: usize, inend: usize, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    splitpoints.clear();
    let mut store = Lz77Store::new();

    /* Unintuitively, Using a simple LZ77 method here instead of lz77_optimal
    results in better blocks. */
    {
        let mut state = ZopfliBlockState::new_without_cache(options, instart, inend);
        store.greedy(&mut state, in_data, instart, inend);
    }

    let mut lz77splitpoints = Vec::with_capacity(maxblocks);
    blocksplit_lz77(options, &store, maxblocks, &mut lz77splitpoints);

    let nlz77points = lz77splitpoints.len();

    /* Convert LZ77 positions to positions in the uncompressed input. */
    let mut pos = instart;
    if nlz77points > 0 {
        for (i, item) in store.litlens.iter().enumerate() {
            let length = item.size();
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == nlz77points {
                    break;
                }
            }
            pos += length;
        }
    }
    assert!(splitpoints.len() == nlz77points);
}
<commit_msg>Start and end only need to be mut in the else case<commit_after>use std::f64;

use deflate::calculate_block_size_auto_type;
use lz77::{Lz77Store, ZopfliBlockState};
use Options;

/// Finds minimum of function `f(i)` where `i` is of type `usize`, `f(i)` is of type
/// `f64`, `i` is in range `start-end` (excluding `end`).
/// Returns the index to the minimum and the minimum value.
fn find_minimum<F>(f: F, start: usize, end: usize) -> (usize, f64)
    where F: Fn(usize) -> f64
{
    if end - start < 1024 {
        let mut best = f64::MAX;
        let mut result = start;
        for i in start..end {
            let v = f(i);
            if v < best {
                best = v;
                result = i;
            }
        }
        (result, best)
    } else {
        /* Try to find minimum faster by recursively checking multiple points. */
        let mut start = start;
        let mut end = end;
        let num = 9;  /* Good value: 9. ?!?!?!?! */
        let mut p = vec![0; num];
        let mut vp = vec![0.0; num];
        let mut lastbest = f64::MAX;
        let mut pos = start;

        while end - start > num {
            let mut besti = 0;
            let mut best = f64::MAX;
            let multiplier = (end - start) / (num + 1);
            for i in 0..num {
                p[i] = start + (i + 1) * multiplier;
                vp[i] = f(p[i]);
                if vp[i] < best {
                    best = vp[i];
                    besti = i;
                }
            }
            if best > lastbest {
                break;
            }

            start = if besti == 0 { start } else { p[besti - 1] };
            end = if besti == num - 1 { end } else { p[besti + 1] };

            pos = p[besti];
            lastbest = best;
        }
        (pos, lastbest)
    }
}

/// Returns estimated cost of a block in bits.  It includes the size to encode the
/// tree and the size to encode all literal, length and distance symbols and their
/// extra bits.
///
/// litlens: lz77 lit/lengths
/// dists: ll77 distances
/// lstart: start of block
/// lend: end of block (not inclusive)
fn estimate_cost(lz77: &Lz77Store, lstart: usize, lend: usize) -> f64 {
    calculate_block_size_auto_type(lz77, lstart, lend)
}

/// Finds next block to try to split, the largest of the available ones.
/// The largest is chosen to make sure that if only a limited amount of blocks is
/// requested, their sizes are spread evenly.
/// lz77size: the size of the LL77 data, which is the size of the done array here.
/// done: array indicating which blocks starting at that position are no longer
///     splittable (splitting them increases rather than decreases cost).
/// splitpoints: the splitpoints found so far.
/// npoints: the amount of splitpoints found so far.
/// lstart: output variable, giving start of block.
/// lend: output variable, giving end of block.
/// returns 1 if a block was found, 0 if no block found (all are done).
fn find_largest_splittable_block(lz77size: usize, done: &[u8], splitpoints: &[usize]) -> Option<(usize, usize)> {
    let mut longest = 0;
    let mut found = None;

    let mut last = 0;

    for &item in splitpoints.iter() {
        if done[last] == 0 && item - last > longest {
            found = Some((last, item));
            longest = item - last;
        }
        last = item;
    }

    let end = lz77size - 1;
    if done[last] == 0 && end - last > longest {
        found = Some((last, end));
    }

    found
}

/// Prints the block split points as decimal and hex values in the terminal.
fn print_block_split_points(lz77: &Lz77Store, lz77splitpoints: &[usize]) {
    let nlz77points = lz77splitpoints.len();
    let mut splitpoints = Vec::with_capacity(nlz77points);

    /* The input is given as lz77 indices, but we want to see the uncompressed
    index values. */
    let mut pos = 0;
    if nlz77points > 0 {
        for (i, item) in lz77.litlens.iter().enumerate() {
            let length = item.size();
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == nlz77points {
                    break;
                }
            }
            pos += length;
        }
    }
    assert!(splitpoints.len() == nlz77points);

    println!("block split points: {} (hex: {})", splitpoints.iter().map(|&sp| format!("{}", sp)).collect::<Vec<_>>().join(" "), splitpoints.iter().map(|&sp| format!("{:x}", sp)).collect::<Vec<_>>().join(" "));
}

/// Does blocksplitting on LZ77 data.
/// The output splitpoints are indices in the LZ77 data.
/// maxblocks: set a limit to the amount of blocks. Set to 0 to mean no limit.
pub fn blocksplit_lz77(options: &Options, lz77: &Lz77Store, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    if lz77.size() < 10 {
        return;  /* This code fails on tiny files. */
    }

    let mut numblocks = 1;
    let mut done = vec![0; lz77.size()];
    let mut lstart = 0;
    let mut lend = lz77.size();

    while maxblocks != 0 && numblocks < maxblocks {
        assert!(lstart < lend);
        let find_minimum_result = find_minimum(|i|
            estimate_cost(lz77, lstart, i) + estimate_cost(lz77, i, lend), lstart + 1, lend
        );
        let llpos = find_minimum_result.0;
        let splitcost = find_minimum_result.1;

        assert!(llpos > lstart);
        assert!(llpos < lend);

        let origcost = estimate_cost(lz77, lstart, lend);

        if splitcost > origcost || llpos == lstart + 1 || llpos == lend {
            done[lstart] = 1;
        } else {
            splitpoints.push(llpos);
            splitpoints.sort();
            numblocks += 1;
        }

        // If `find_largest_splittable_block` returns `None`, no further split will
        // likely reduce compression.
        let is_finished = find_largest_splittable_block(lz77.size(), &done, splitpoints)
            .map_or(true, |(start, end)| {
                lstart = start;
                lend = end;
                lend - lstart < 10
            });

        if is_finished { break }
    }

    if options.verbose {
        print_block_split_points(lz77, splitpoints);
    }
}

/// Does blocksplitting on uncompressed data.
/// The output splitpoints are indices in the uncompressed bytes.
///
/// options: general program options.
/// in: uncompressed input data
/// instart: where to start splitting
/// inend: where to end splitting (not inclusive)
/// maxblocks: maximum amount of blocks to split into, or 0 for no limit
/// splitpoints: dynamic array to put the resulting split point coordinates into.
///   The coordinates are indices in the input array.
/// npoints: pointer to amount of splitpoints, for the dynamic array. The amount of
///   blocks is the amount of splitpoitns + 1.
pub fn blocksplit(options: &Options, in_data: &[u8], instart: usize, inend: usize, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    splitpoints.clear();
    let mut store = Lz77Store::new();

    /* Unintuitively, Using a simple LZ77 method here instead of lz77_optimal
    results in better blocks. */
    {
        let mut state = ZopfliBlockState::new_without_cache(options, instart, inend);
        store.greedy(&mut state, in_data, instart, inend);
    }

    let mut lz77splitpoints = Vec::with_capacity(maxblocks);
    blocksplit_lz77(options, &store, maxblocks, &mut lz77splitpoints);

    let nlz77points = lz77splitpoints.len();

    /* Convert LZ77 positions to positions in the uncompressed input. */
    let mut pos = instart;
    if nlz77points > 0 {
        for (i, item) in store.litlens.iter().enumerate() {
            let length = item.size();
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == nlz77points {
                    break;
                }
            }
            pos += length;
        }
    }
    assert!(splitpoints.len() == nlz77points);
}
<|endoftext|>


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

use std::num::{Zero, zero, One, one, sqrt};

use angle::{Rad, atan2, acos};
use array::{Array, build};

/// A 2-dimensional vector.
#[deriving(Eq, Clone, Zero)]
pub struct Vec2<S> { x: S, y: S }

/// A 3-dimensional vector.
#[deriving(Eq, Clone, Zero)]
pub struct Vec3<S> { x: S, y: S, z: S }

/// A 4-dimensional vector.
#[deriving(Eq, Clone, Zero)]
pub struct Vec4<S> { x: S, y: S, z: S, w: S }

// Conversion traits
pub trait ToVec2<S: Primitive> { fn to_vec2(&self) -> Vec2<S>; }
pub trait ToVec3<S: Primitive> { fn to_vec3(&self) -> Vec3<S>; }
pub trait ToVec4<S: Primitive> { fn to_vec4(&self) -> Vec4<S>; }

// Utility macro for generating associated functions for the vectors
macro_rules! vec(
    (impl $Self:ident <$S:ident> { $($field:ident),+ }) => (
        impl<$S: Primitive> $Self<$S> {
            #[inline]
            pub fn new($($field: $S),+) -> $Self<$S> {
                $Self { $($field: $field),+ }
            }

            /// Construct a vector from a single value.
            #[inline]
            pub fn from_value(value: $S) -> $Self<$S> {
                $Self { $($field: value.clone()),+ }
            }

            /// The additive identity of the vector.
            #[inline]
            pub fn zero() -> $Self<$S> { $Self::from_value(zero()) }

            /// The additive identity of the vector.
            #[inline]
            pub fn ident() -> $Self<$S> { $Self::from_value(one()) }
        }
    )
)

vec!(impl Vec2<S> { x, y })
vec!(impl Vec3<S> { x, y, z })
vec!(impl Vec4<S> { x, y, z, w })

impl<S: Primitive> Vec2<S> {
    #[inline] pub fn unit_x() -> Vec2<S> { Vec2::new(one(), zero()) }
    #[inline] pub fn unit_y() -> Vec2<S> { Vec2::new(zero(), one()) }
}

impl<S: Primitive> Vec3<S> {
    #[inline] pub fn unit_x() -> Vec3<S> { Vec3::new(one(), zero(), zero()) }
    #[inline] pub fn unit_y() -> Vec3<S> { Vec3::new(zero(), one(), zero()) }
    #[inline] pub fn unit_z() -> Vec3<S> { Vec3::new(zero(), zero(), one()) }
}

impl<S: Primitive> Vec4<S> {
    #[inline] pub fn unit_x() -> Vec4<S> { Vec4::new(one(), zero(), zero(), zero()) }
    #[inline] pub fn unit_y() -> Vec4<S> { Vec4::new(zero(), one(), zero(), zero()) }
    #[inline] pub fn unit_z() -> Vec4<S> { Vec4::new(zero(), zero(), one(), zero()) }
    #[inline] pub fn unit_w() -> Vec4<S> { Vec4::new(zero(), zero(), zero(), one()) }
}

array!(impl<S> Vec2<S> -> [S, ..2] _2)
array!(impl<S> Vec3<S> -> [S, ..3] _3)
array!(impl<S> Vec4<S> -> [S, ..4] _4)

approx_eq!(impl<S> Vec2<S>)
approx_eq!(impl<S> Vec3<S>)
approx_eq!(impl<S> Vec4<S>)

/// A trait that specifies a range of numeric operations for vectors. Not all
/// of these make sense from a linear algebra point of view, but are included
/// for pragmatic reasons.
pub trait Vector
<
    S: Primitive,
    Slice
>
:   Array<S, Slice>
+   Neg<Self>
+   Zero + One
{
    #[inline] fn add_s(&self, s: S) -> Self { build(|i| self.i(i).add(&s)) }
    #[inline] fn sub_s(&self, s: S) -> Self { build(|i| self.i(i).sub(&s)) }
    #[inline] fn mul_s(&self, s: S) -> Self { build(|i| self.i(i).mul(&s)) }
    #[inline] fn div_s(&self, s: S) -> Self { build(|i| self.i(i).div(&s)) }
    #[inline] fn rem_s(&self, s: S) -> Self { build(|i| self.i(i).rem(&s)) }

    #[inline] fn add_v(&self, other: &Self) -> Self { build(|i| self.i(i).add(other.i(i))) }
    #[inline] fn sub_v(&self, other: &Self) -> Self { build(|i| self.i(i).sub(other.i(i))) }
    #[inline] fn mul_v(&self, other: &Self) -> Self { build(|i| self.i(i).mul(other.i(i))) }
    #[inline] fn div_v(&self, other: &Self) -> Self { build(|i| self.i(i).div(other.i(i))) }
    #[inline] fn rem_v(&self, other: &Self) -> Self { build(|i| self.i(i).rem(other.i(i))) }

    #[inline] fn neg_self(&mut self) { self.each_mut(|_, x| *x = x.neg()) }

    #[inline] fn add_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.add(&s)) }
    #[inline] fn sub_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.sub(&s)) }
    #[inline] fn mul_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.mul(&s)) }
    #[inline] fn div_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.div(&s)) }
    #[inline] fn rem_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.rem(&s)) }

    #[inline] fn add_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.add(other.i(i))) }
    #[inline] fn sub_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.sub(other.i(i))) }
    #[inline] fn mul_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.mul(other.i(i))) }
    #[inline] fn div_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.div(other.i(i))) }
    #[inline] fn rem_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.rem(other.i(i))) }

    /// The sum of each component of the vector.
    #[inline] fn comp_add(&self) -> S { self.fold(|a, b| a.add(b)) }

    /// The product of each component of the vector.
    #[inline] fn comp_mul(&self) -> S { self.fold(|a, b| a.mul(b)) }

    /// Vector dot product.
    #[inline] fn dot(&self, other: &Self) -> S { self.mul_v(other).comp_add() }

    /// The minimum component of the vector.
    #[inline] fn comp_min(&self) -> S { self.iter().min().unwrap().clone() }

    /// The maximum component of the vector.
    #[inline] fn comp_max(&self) -> S { self.iter().max().unwrap().clone() }
}

#[inline] fn dot<S: Primitive, Slice, V: Vector<S, Slice>>(a: V, b: V) -> S { a.dot(&b) }

impl<S: Primitive> One for Vec2<S> { #[inline] fn one() -> Vec2<S> { Vec2::ident() } }
impl<S: Primitive> One for Vec3<S> { #[inline] fn one() -> Vec3<S> { Vec3::ident() } }
impl<S: Primitive> One for Vec4<S> { #[inline] fn one() -> Vec4<S> { Vec4::ident() } }

impl<S: Primitive> Neg<Vec2<S>> for Vec2<S> { #[inline] fn neg(&self) -> Vec2<S> { build(|i| self.i(i).neg()) } }
impl<S: Primitive> Neg<Vec3<S>> for Vec3<S> { #[inline] fn neg(&self) -> Vec3<S> { build(|i| self.i(i).neg()) } }
impl<S: Primitive> Neg<Vec4<S>> for Vec4<S> { #[inline] fn neg(&self) -> Vec4<S> { build(|i| self.i(i).neg()) } }

macro_rules! vector(
    (impl $Self:ident <$S:ident> $Slice:ty { $x:ident, $($xs:ident),+ }) => (
        impl<$S: Primitive> Vector<$S, $Slice> for $Self<$S>;
    )
)

vector!(impl Vec2<S> [S, ..2] { x, y })
vector!(impl Vec3<S> [S, ..3] { x, y, z })
vector!(impl Vec4<S> [S, ..4] { x, y, z, w })

/// Operations specific to numeric two-dimensional vectors.
impl<S: Primitive> Vec2<S> {
    /// The perpendicular dot product of the vector and `other`.
    #[inline]
    pub fn perp_dot(&self, other: &Vec2<S>) -> S {
        (self.x * other.y) - (self.y * other.x)
    }
}

/// Operations specific to numeric three-dimensional vectors.
impl<S: Primitive> Vec3<S> {
    /// Returns the cross product of the vector and `other`.
    #[inline]
    pub fn cross(&self, other: &Vec3<S>) -> Vec3<S> {
        Vec3::new((self.y * other.z) - (self.z * other.y),
                  (self.z * other.x) - (self.x * other.z),
                  (self.x * other.y) - (self.y * other.x))
    }

    /// Calculates the cross product of the vector and `other`, then stores the
    /// result in `self`.
    #[inline]
    pub fn cross_self(&mut self, other: &Vec3<S>) {
        *self = self.cross(other)
    }
}

/// Specifies geometric operations for vectors. This is only implemented for
/// 2-dimensional and 3-dimensional vectors.
pub trait EuclideanVector
<
    S: Float,
    Slice
>
:   Vector<S, Slice>
+   ApproxEq<S>
{
    /// Returns `true` if the vector is perpendicular (at right angles to)
    /// the other vector.
    fn is_perpendicular(&self, other: &Self) -> bool {
        self.dot(other).approx_eq(&zero())
    }

    /// Returns the squared length of the vector. This does not perform an
    /// expensive square root operation like in the `length` method and can
    /// therefore be more efficient for comparing the lengths of two vectors.
    #[inline]
    fn length2(&self) -> S {
        self.dot(self)
    }

    /// The norm of the vector.
    #[inline]
    fn length(&self) -> S {
        sqrt(self.dot(self))
    }

    /// The angle between the vector and `other`.
    fn angle(&self, other: &Self) -> Rad<S>;

    /// Returns a vector with the same direction, but with a `length` (or
    /// `norm`) of `1`.
    #[inline]
    fn normalize(&self) -> Self {
        self.normalize_to(one::<S>())
    }

    /// Returns a vector with the same direction and a given `length`.
    #[inline]
    fn normalize_to(&self, length: S) -> Self {
        self.mul_s(length / self.length())
    }

    /// Returns the result of linarly interpolating the length of the vector
    /// towards the length of `other` by the specified amount.
    #[inline]
    fn lerp(&self, other: &Self, amount: S) -> Self {
        self.add_v(&other.sub_v(self).mul_s(amount))
    }

    /// Normalises the vector to a length of `1`.
    #[inline]
    fn normalize_self(&mut self) {
        let rlen = self.length().recip();
        self.mul_self_s(rlen);
    }

    /// Normalizes the vector to `length`.
    #[inline]
    fn normalize_self_to(&mut self, length: S) {
        let n = length / self.length();
        self.mul_self_s(n);
    }

    /// Linearly interpolates the length of the vector towards the length of
    /// `other` by the specified amount.
    fn lerp_self(&mut self, other: &Self, amount: S) {
        let v = other.sub_v(self).mul_s(amount);
        self.add_self_v(&v);
    }
}

impl<S: Float> EuclideanVector<S, [S, ..2]> for Vec2<S> {
    #[inline]
    fn angle(&self, other: &Vec2<S>) -> Rad<S> {
        atan2(self.perp_dot(other), self.dot(other))
    }
}

impl<S: Float> EuclideanVector<S, [S, ..3]> for Vec3<S> {
    #[inline]
    fn angle(&self, other: &Vec3<S>) -> Rad<S> {
        atan2(self.cross(other).length(), self.dot(other))
    }
}

impl<S: Float> EuclideanVector<S, [S, ..4]> for Vec4<S> {
    #[inline]
    fn angle(&self, other: &Vec4<S>) -> Rad<S> {
        acos(self.dot(other) / (self.length() * other.length()))
    }
}

impl<S> ToStr for Vec2<S> {
    fn to_str(&self) -> ~str {
        fmt!("[%?, %?]", self.x, self.y)
    }
}

impl<S> ToStr for Vec3<S> {
    fn to_str(&self) -> ~str {
        fmt!("[%?, %?, %?]", self.x, self.y, self.z)
    }
}

impl<S> ToStr for Vec4<S> {
    fn to_str(&self) -> ~str {
        fmt!("[%?, %?, %?, %?]", self.x, self.y, self.z, self.w)
    }
}
<commit_msg>Remove vector! macro<commit_after>// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::num::{Zero, zero, One, one, sqrt};

use angle::{Rad, atan2, acos};
use array::{Array, build};

/// A 2-dimensional vector.
#[deriving(Eq, Clone, Zero)]
pub struct Vec2<S> { x: S, y: S }

/// A 3-dimensional vector.
#[deriving(Eq, Clone, Zero)]
pub struct Vec3<S> { x: S, y: S, z: S }

/// A 4-dimensional vector.
#[deriving(Eq, Clone, Zero)]
pub struct Vec4<S> { x: S, y: S, z: S, w: S }

// Conversion traits
pub trait ToVec2<S: Primitive> { fn to_vec2(&self) -> Vec2<S>; }
pub trait ToVec3<S: Primitive> { fn to_vec3(&self) -> Vec3<S>; }
pub trait ToVec4<S: Primitive> { fn to_vec4(&self) -> Vec4<S>; }

// Utility macro for generating associated functions for the vectors
macro_rules! vec(
    (impl $Self:ident <$S:ident> { $($field:ident),+ }) => (
        impl<$S: Primitive> $Self<$S> {
            #[inline]
            pub fn new($($field: $S),+) -> $Self<$S> {
                $Self { $($field: $field),+ }
            }

            /// Construct a vector from a single value.
            #[inline]
            pub fn from_value(value: $S) -> $Self<$S> {
                $Self { $($field: value.clone()),+ }
            }

            /// The additive identity of the vector.
            #[inline]
            pub fn zero() -> $Self<$S> { $Self::from_value(zero()) }

            /// The additive identity of the vector.
            #[inline]
            pub fn ident() -> $Self<$S> { $Self::from_value(one()) }
        }
    )
)

vec!(impl Vec2<S> { x, y })
vec!(impl Vec3<S> { x, y, z })
vec!(impl Vec4<S> { x, y, z, w })

impl<S: Primitive> Vec2<S> {
    #[inline] pub fn unit_x() -> Vec2<S> { Vec2::new(one(), zero()) }
    #[inline] pub fn unit_y() -> Vec2<S> { Vec2::new(zero(), one()) }
}

impl<S: Primitive> Vec3<S> {
    #[inline] pub fn unit_x() -> Vec3<S> { Vec3::new(one(), zero(), zero()) }
    #[inline] pub fn unit_y() -> Vec3<S> { Vec3::new(zero(), one(), zero()) }
    #[inline] pub fn unit_z() -> Vec3<S> { Vec3::new(zero(), zero(), one()) }
}

impl<S: Primitive> Vec4<S> {
    #[inline] pub fn unit_x() -> Vec4<S> { Vec4::new(one(), zero(), zero(), zero()) }
    #[inline] pub fn unit_y() -> Vec4<S> { Vec4::new(zero(), one(), zero(), zero()) }
    #[inline] pub fn unit_z() -> Vec4<S> { Vec4::new(zero(), zero(), one(), zero()) }
    #[inline] pub fn unit_w() -> Vec4<S> { Vec4::new(zero(), zero(), zero(), one()) }
}

array!(impl<S> Vec2<S> -> [S, ..2] _2)
array!(impl<S> Vec3<S> -> [S, ..3] _3)
array!(impl<S> Vec4<S> -> [S, ..4] _4)

approx_eq!(impl<S> Vec2<S>)
approx_eq!(impl<S> Vec3<S>)
approx_eq!(impl<S> Vec4<S>)

/// A trait that specifies a range of numeric operations for vectors. Not all
/// of these make sense from a linear algebra point of view, but are included
/// for pragmatic reasons.
pub trait Vector
<
    S: Primitive,
    Slice
>
:   Array<S, Slice>
+   Neg<Self>
+   Zero + One
{
    #[inline] fn add_s(&self, s: S) -> Self { build(|i| self.i(i).add(&s)) }
    #[inline] fn sub_s(&self, s: S) -> Self { build(|i| self.i(i).sub(&s)) }
    #[inline] fn mul_s(&self, s: S) -> Self { build(|i| self.i(i).mul(&s)) }
    #[inline] fn div_s(&self, s: S) -> Self { build(|i| self.i(i).div(&s)) }
    #[inline] fn rem_s(&self, s: S) -> Self { build(|i| self.i(i).rem(&s)) }

    #[inline] fn add_v(&self, other: &Self) -> Self { build(|i| self.i(i).add(other.i(i))) }
    #[inline] fn sub_v(&self, other: &Self) -> Self { build(|i| self.i(i).sub(other.i(i))) }
    #[inline] fn mul_v(&self, other: &Self) -> Self { build(|i| self.i(i).mul(other.i(i))) }
    #[inline] fn div_v(&self, other: &Self) -> Self { build(|i| self.i(i).div(other.i(i))) }
    #[inline] fn rem_v(&self, other: &Self) -> Self { build(|i| self.i(i).rem(other.i(i))) }

    #[inline] fn neg_self(&mut self) { self.each_mut(|_, x| *x = x.neg()) }

    #[inline] fn add_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.add(&s)) }
    #[inline] fn sub_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.sub(&s)) }
    #[inline] fn mul_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.mul(&s)) }
    #[inline] fn div_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.div(&s)) }
    #[inline] fn rem_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.rem(&s)) }

    #[inline] fn add_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.add(other.i(i))) }
    #[inline] fn sub_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.sub(other.i(i))) }
    #[inline] fn mul_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.mul(other.i(i))) }
    #[inline] fn div_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.div(other.i(i))) }
    #[inline] fn rem_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.rem(other.i(i))) }

    /// The sum of each component of the vector.
    #[inline] fn comp_add(&self) -> S { self.fold(|a, b| a.add(b)) }

    /// The product of each component of the vector.
    #[inline] fn comp_mul(&self) -> S { self.fold(|a, b| a.mul(b)) }

    /// Vector dot product.
    #[inline] fn dot(&self, other: &Self) -> S { self.mul_v(other).comp_add() }

    /// The minimum component of the vector.
    #[inline] fn comp_min(&self) -> S { self.iter().min().unwrap().clone() }

    /// The maximum component of the vector.
    #[inline] fn comp_max(&self) -> S { self.iter().max().unwrap().clone() }
}

#[inline] fn dot<S: Primitive, Slice, V: Vector<S, Slice>>(a: V, b: V) -> S { a.dot(&b) }

impl<S: Primitive> One for Vec2<S> { #[inline] fn one() -> Vec2<S> { Vec2::ident() } }
impl<S: Primitive> One for Vec3<S> { #[inline] fn one() -> Vec3<S> { Vec3::ident() } }
impl<S: Primitive> One for Vec4<S> { #[inline] fn one() -> Vec4<S> { Vec4::ident() } }

impl<S: Primitive> Neg<Vec2<S>> for Vec2<S> { #[inline] fn neg(&self) -> Vec2<S> { build(|i| self.i(i).neg()) } }
impl<S: Primitive> Neg<Vec3<S>> for Vec3<S> { #[inline] fn neg(&self) -> Vec3<S> { build(|i| self.i(i).neg()) } }
impl<S: Primitive> Neg<Vec4<S>> for Vec4<S> { #[inline] fn neg(&self) -> Vec4<S> { build(|i| self.i(i).neg()) } }

impl<S: Primitive> Vector<S, [S, ..2]> for Vec2<S>;
impl<S: Primitive> Vector<S, [S, ..3]> for Vec3<S>;
impl<S: Primitive> Vector<S, [S, ..4]> for Vec4<S>;

/// Operations specific to numeric two-dimensional vectors.
impl<S: Primitive> Vec2<S> {
    /// The perpendicular dot product of the vector and `other`.
    #[inline]
    pub fn perp_dot(&self, other: &Vec2<S>) -> S {
        (self.x * other.y) - (self.y * other.x)
    }
}

/// Operations specific to numeric three-dimensional vectors.
impl<S: Primitive> Vec3<S> {
    /// Returns the cross product of the vector and `other`.
    #[inline]
    pub fn cross(&self, other: &Vec3<S>) -> Vec3<S> {
        Vec3::new((self.y * other.z) - (self.z * other.y),
                  (self.z * other.x) - (self.x * other.z),
                  (self.x * other.y) - (self.y * other.x))
    }

    /// Calculates the cross product of the vector and `other`, then stores the
    /// result in `self`.
    #[inline]
    pub fn cross_self(&mut self, other: &Vec3<S>) {
        *self = self.cross(other)
    }
}

/// Specifies geometric operations for vectors. This is only implemented for
/// 2-dimensional and 3-dimensional vectors.
pub trait EuclideanVector
<
    S: Float,
    Slice
>
:   Vector<S, Slice>
+   ApproxEq<S>
{
    /// Returns `true` if the vector is perpendicular (at right angles to)
    /// the other vector.
    fn is_perpendicular(&self, other: &Self) -> bool {
        self.dot(other).approx_eq(&zero())
    }

    /// Returns the squared length of the vector. This does not perform an
    /// expensive square root operation like in the `length` method and can
    /// therefore be more efficient for comparing the lengths of two vectors.
    #[inline]
    fn length2(&self) -> S {
        self.dot(self)
    }

    /// The norm of the vector.
    #[inline]
    fn length(&self) -> S {
        sqrt(self.dot(self))
    }

    /// The angle between the vector and `other`.
    fn angle(&self, other: &Self) -> Rad<S>;

    /// Returns a vector with the same direction, but with a `length` (or
    /// `norm`) of `1`.
    #[inline]
    fn normalize(&self) -> Self {
        self.normalize_to(one::<S>())
    }

    /// Returns a vector with the same direction and a given `length`.
    #[inline]
    fn normalize_to(&self, length: S) -> Self {
        self.mul_s(length / self.length())
    }

    /// Returns the result of linarly interpolating the length of the vector
    /// towards the length of `other` by the specified amount.
    #[inline]
    fn lerp(&self, other: &Self, amount: S) -> Self {
        self.add_v(&other.sub_v(self).mul_s(amount))
    }

    /// Normalises the vector to a length of `1`.
    #[inline]
    fn normalize_self(&mut self) {
        let rlen = self.length().recip();
        self.mul_self_s(rlen);
    }

    /// Normalizes the vector to `length`.
    #[inline]
    fn normalize_self_to(&mut self, length: S) {
        let n = length / self.length();
        self.mul_self_s(n);
    }

    /// Linearly interpolates the length of the vector towards the length of
    /// `other` by the specified amount.
    fn lerp_self(&mut self, other: &Self, amount: S) {
        let v = other.sub_v(self).mul_s(amount);
        self.add_self_v(&v);
    }
}

impl<S: Float> EuclideanVector<S, [S, ..2]> for Vec2<S> {
    #[inline]
    fn angle(&self, other: &Vec2<S>) -> Rad<S> {
        atan2(self.perp_dot(other), self.dot(other))
    }
}

impl<S: Float> EuclideanVector<S, [S, ..3]> for Vec3<S> {
    #[inline]
    fn angle(&self, other: &Vec3<S>) -> Rad<S> {
        atan2(self.cross(other).length(), self.dot(other))
    }
}

impl<S: Float> EuclideanVector<S, [S, ..4]> for Vec4<S> {
    #[inline]
    fn angle(&self, other: &Vec4<S>) -> Rad<S> {
        acos(self.dot(other) / (self.length() * other.length()))
    }
}

impl<S> ToStr for Vec2<S> {
    fn to_str(&self) -> ~str {
        fmt!("[%?, %?]", self.x, self.y)
    }
}

impl<S> ToStr for Vec3<S> {
    fn to_str(&self) -> ~str {
        fmt!("[%?, %?, %?]", self.x, self.y, self.z)
    }
}

impl<S> ToStr for Vec4<S> {
    fn to_str(&self) -> ~str {
        fmt!("[%?, %?, %?, %?]", self.x, self.y, self.z, self.w)
    }
}
<|endoftext|>


<commit_before>use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use graphics::Dimensions;
use cgmath;
use cgmath::{Matrix4, Point3, Vector3};
use specs;
use gfx_app::graphics::load_texture;
use character::gfx_macros::{pipe, VertexData, CharacterSheet, Position};
use game::gfx_macros::Projection;
use game::constants::{ASPECT_RATIO, VIEW_DISTANCE, RUN_SPRITE_OFFSET};
use gfx_app::mouse_controls::MouseInputState;
use terrain::controls::CameraInputState;
use character::controls::CharacterInputState;
use data;
use character::orientation::{Orientation, Stance};
use character::character::{CharacterSprite, CharacterData};

mod audio;
pub mod gfx_macros;
pub mod character;
pub mod orientation;
pub mod controls;

const SHADER_VERT: &'static [u8] = include_bytes!("character.v.glsl");
const SHADER_FRAG: &'static [u8] = include_bytes!("character.f.glsl");

impl VertexData {
  fn new(pos: [f32; 3], buf_pos: [f32; 2]) -> VertexData {
    VertexData {
      pos,
      buf_pos,
    }
  }
}

pub struct CharacterDrawable {
  projection: Projection,
  position: Position,
  orientation: Orientation,
  stance: Stance,
  direction: Orientation,
  audio: audio::CharacterAudio
}

impl CharacterDrawable {
  pub fn new() -> CharacterDrawable {
    let view: Matrix4<f32> = Matrix4::look_at(
      Point3::new(0.0, 0.0, VIEW_DISTANCE),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    );

    let aspect_ratio: f32 = ASPECT_RATIO;

    CharacterDrawable {
      projection: Projection {
        model: Matrix4::from(view).into(),
        view: view.into(),
        proj: cgmath::perspective(cgmath::Deg(60.0f32), aspect_ratio, 0.1, 4000.0).into(),
      },
      position: Position {
        position: [0.0, 0.0],
      },
      orientation: Orientation::Right,
      stance: Stance::Normal,
      direction: Orientation::Right,
      audio: audio::CharacterAudio::new(),
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState, mouse_input: &mut MouseInputState) {
    self.projection = *world_to_clip;
    let new_position = Position {
      position: [ci.x_movement, ci.y_movement]
    };

    if let Some(_) = mouse_input.left_click_point {
      self.stance = Stance::Firing;
      self.audio.play_pistol();
    } else {
      self.stance = Stance::Normal;
    }

    let dx = new_position.position[0] - self.position.position[0];
    let dy = new_position.position[1] - self.position.position[1];
    self.orientation =
      if dx == 0.0 && dy < 0.0       { Orientation::Down }
      else if dx > 0.0 && dy < 0.0   { Orientation::DownRight }
      else if dx < 0.0 && dy < 0.0   { Orientation::DownLeft }
      else if dx == 0.0 && dy == 0.0 { Orientation::Still }
      else if dx > 0.0 && dy == 0.0  { Orientation::Right }
      else if dx < 0.0 && dy == 0.0  { Orientation::Left }
      else if dx == 0.0 && dy > 0.0  { Orientation::Up }
      else if dx > 0.0 && dy > 0.0   { Orientation::UpRight }
      else if dx < 0.0 && dy > 0.0   { Orientation::UpLeft }
      else { unreachable!() };
    self.position = new_position;
  }
}

impl specs::Component for CharacterDrawable {
  type Storage = specs::VecStorage<CharacterDrawable>;
}

pub struct DrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, pipe::Data<R>>,
  data: Vec<CharacterData>,
}

impl<R: gfx::Resources> DrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> DrawSystem<R>
    where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let tilesheet_bytes = &include_bytes!("../../assets/character.png")[..];

    let vertex_data: Vec<VertexData> =
      vec![
        VertexData::new([-20.0, -28.0, 0.0], [0.0, 1.0]),
        VertexData::new([20.0, -28.0, 0.0], [1.0, 1.0]),
        VertexData::new([20.0, 28.0, 0.0], [1.0, 0.0]),
        VertexData::new([-20.0, -28.0, 0.0], [0.0, 1.0]),
        VertexData::new([20.0, 28.0, 0.0], [1.0, 0.0]),
        VertexData::new([-20.0, 28.0, 0.0], [0.0, 0.0]),
      ];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, ());

    let char_texture = load_texture(factory, tilesheet_bytes).unwrap();
    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              pipe::new())
      .unwrap();

    let pipeline_data = pipe::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (char_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_character();

    DrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data
    }
  }

  fn get_next_sprite(&self, character_idx: usize, mut drawable: &mut CharacterDrawable) -> CharacterSheet {
    let charsheet_total_width = 16128f32;
    let offset = 2.0;

    let char_sprite = if drawable.orientation == Orientation::Still && drawable.stance == Stance::Normal {
      let sprite_idx = (drawable.direction as usize * 28 + RUN_SPRITE_OFFSET) as usize;
      (&self.data[sprite_idx], sprite_idx)
    } else if drawable.stance == Stance::Normal {
      drawable.direction = drawable.orientation;
      let sprite_idx = (drawable.orientation as usize * 28 + character_idx + RUN_SPRITE_OFFSET) as usize;
      (&self.data[sprite_idx], sprite_idx)
    } else {
      let idx = (character_idx as f32 * 4.0 / 14.0).floor() as usize;
      let sprite_idx = (drawable.orientation as usize * 8 + idx) as usize;
      (&self.data[sprite_idx], sprite_idx)
    };

    let elements_x = charsheet_total_width / (char_sprite.0.data[2] + offset);
    let char = CharacterSheet {
      div: elements_x,
      index: char_sprite.1 as f32
    };
    char
  }

  pub fn draw<C>(&mut self,
                 mut drawable: &mut CharacterDrawable,
                 character: &CharacterSprite,
                 encoder: &mut gfx::Encoder<R, C>)
    where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb, &mut self.get_next_sprite(character.character_idx, &mut drawable));
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<C> specs::System<C> for PreDrawSystem {
  fn run(&mut self, arg: specs::RunArg, _: C) {
    use specs::Join;
    let (mut character, dim, mut terrain_input, mut character_input, mut mouse_input) =
      arg.fetch(|w| (
        w.write::<CharacterDrawable>(),
        w.read_resource::<Dimensions>(),
        w.write::<CameraInputState>(),
        w.write::<CharacterInputState>(),
        w.write::<MouseInputState>()));

    for (c, i, ci, mi) in (&mut character, &mut terrain_input, &mut character_input, &mut mouse_input).join() {
      let world_to_clip = dim.world_to_projection(i);
      c.update(&world_to_clip, ci, mi);
    }
  }
}
<commit_msg>Remove unneeded mutable<commit_after>use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use graphics::Dimensions;
use cgmath;
use cgmath::{Matrix4, Point3, Vector3};
use specs;
use gfx_app::graphics::load_texture;
use character::gfx_macros::{pipe, VertexData, CharacterSheet, Position};
use game::gfx_macros::Projection;
use game::constants::{ASPECT_RATIO, VIEW_DISTANCE, RUN_SPRITE_OFFSET};
use gfx_app::mouse_controls::MouseInputState;
use terrain::controls::CameraInputState;
use character::controls::CharacterInputState;
use data;
use character::orientation::{Orientation, Stance};
use character::character::{CharacterSprite, CharacterData};

mod audio;
pub mod gfx_macros;
pub mod character;
pub mod orientation;
pub mod controls;

const SHADER_VERT: &'static [u8] = include_bytes!("character.v.glsl");
const SHADER_FRAG: &'static [u8] = include_bytes!("character.f.glsl");

impl VertexData {
  fn new(pos: [f32; 3], buf_pos: [f32; 2]) -> VertexData {
    VertexData {
      pos,
      buf_pos,
    }
  }
}

pub struct CharacterDrawable {
  projection: Projection,
  position: Position,
  orientation: Orientation,
  stance: Stance,
  direction: Orientation,
  audio: audio::CharacterAudio
}

impl CharacterDrawable {
  pub fn new() -> CharacterDrawable {
    let view: Matrix4<f32> = Matrix4::look_at(
      Point3::new(0.0, 0.0, VIEW_DISTANCE),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    );

    let aspect_ratio: f32 = ASPECT_RATIO;

    CharacterDrawable {
      projection: Projection {
        model: Matrix4::from(view).into(),
        view: view.into(),
        proj: cgmath::perspective(cgmath::Deg(60.0f32), aspect_ratio, 0.1, 4000.0).into(),
      },
      position: Position {
        position: [0.0, 0.0],
      },
      orientation: Orientation::Right,
      stance: Stance::Normal,
      direction: Orientation::Right,
      audio: audio::CharacterAudio::new(),
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState, mouse_input: &mut MouseInputState) {
    self.projection = *world_to_clip;
    let new_position = Position {
      position: [ci.x_movement, ci.y_movement]
    };

    if let Some(_) = mouse_input.left_click_point {
      self.stance = Stance::Firing;
      self.audio.play_pistol();
    } else {
      self.stance = Stance::Normal;
    }

    let dx = new_position.position[0] - self.position.position[0];
    let dy = new_position.position[1] - self.position.position[1];
    self.orientation =
      if dx == 0.0 && dy < 0.0       { Orientation::Down }
      else if dx > 0.0 && dy < 0.0   { Orientation::DownRight }
      else if dx < 0.0 && dy < 0.0   { Orientation::DownLeft }
      else if dx == 0.0 && dy == 0.0 { Orientation::Still }
      else if dx > 0.0 && dy == 0.0  { Orientation::Right }
      else if dx < 0.0 && dy == 0.0  { Orientation::Left }
      else if dx == 0.0 && dy > 0.0  { Orientation::Up }
      else if dx > 0.0 && dy > 0.0   { Orientation::UpRight }
      else if dx < 0.0 && dy > 0.0   { Orientation::UpLeft }
      else { unreachable!() };
    self.position = new_position;
  }
}

impl specs::Component for CharacterDrawable {
  type Storage = specs::VecStorage<CharacterDrawable>;
}

pub struct DrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, pipe::Data<R>>,
  data: Vec<CharacterData>,
}

impl<R: gfx::Resources> DrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> DrawSystem<R>
    where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let tilesheet_bytes = &include_bytes!("../../assets/character.png")[..];

    let vertex_data: Vec<VertexData> =
      vec![
        VertexData::new([-20.0, -28.0, 0.0], [0.0, 1.0]),
        VertexData::new([20.0, -28.0, 0.0], [1.0, 1.0]),
        VertexData::new([20.0, 28.0, 0.0], [1.0, 0.0]),
        VertexData::new([-20.0, -28.0, 0.0], [0.0, 1.0]),
        VertexData::new([20.0, 28.0, 0.0], [1.0, 0.0]),
        VertexData::new([-20.0, 28.0, 0.0], [0.0, 0.0]),
      ];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, ());

    let char_texture = load_texture(factory, tilesheet_bytes).unwrap();
    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              pipe::new())
      .unwrap();

    let pipeline_data = pipe::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (char_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_character();

    DrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data
    }
  }

  fn get_next_sprite(&self, character_idx: usize, drawable: &mut CharacterDrawable) -> CharacterSheet {
    let charsheet_total_width = 16128f32;
    let offset = 2.0;

    let char_sprite = if drawable.orientation == Orientation::Still && drawable.stance == Stance::Normal {
      let sprite_idx = (drawable.direction as usize * 28 + RUN_SPRITE_OFFSET) as usize;
      (&self.data[sprite_idx], sprite_idx)
    } else if drawable.stance == Stance::Normal {
      drawable.direction = drawable.orientation;
      let sprite_idx = (drawable.orientation as usize * 28 + character_idx + RUN_SPRITE_OFFSET) as usize;
      (&self.data[sprite_idx], sprite_idx)
    } else {
      let idx = (character_idx as f32 * 4.0 / 14.0).floor() as usize;
      let sprite_idx = (drawable.orientation as usize * 8 + idx) as usize;
      (&self.data[sprite_idx], sprite_idx)
    };

    let elements_x = charsheet_total_width / (char_sprite.0.data[2] + offset);
    let char = CharacterSheet {
      div: elements_x,
      index: char_sprite.1 as f32
    };
    char
  }

  pub fn draw<C>(&mut self,
                 mut drawable: &mut CharacterDrawable,
                 character: &CharacterSprite,
                 encoder: &mut gfx::Encoder<R, C>)
    where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb, &mut self.get_next_sprite(character.character_idx, &mut drawable));
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<C> specs::System<C> for PreDrawSystem {
  fn run(&mut self, arg: specs::RunArg, _: C) {
    use specs::Join;
    let (mut character, dim, mut terrain_input, mut character_input, mut mouse_input) =
      arg.fetch(|w| (
        w.write::<CharacterDrawable>(),
        w.read_resource::<Dimensions>(),
        w.write::<CameraInputState>(),
        w.write::<CharacterInputState>(),
        w.write::<MouseInputState>()));

    for (c, i, ci, mi) in (&mut character, &mut terrain_input, &mut character_input, &mut mouse_input).join() {
      let world_to_clip = dim.world_to_projection(i);
      c.update(&world_to_clip, ci, mi);
    }
  }
}
<|endoftext|>


<commit_before>// FIXME: Most of these should be uints.

const int rc_base_field_refcnt = 0;

// FIXME: import from std.dbg when imported consts work.
const uint const_refcount = 0x7bad_face_u;

const int task_field_refcnt = 0;
const int task_field_stk = 2;
const int task_field_runtime_sp = 3;
const int task_field_rust_sp = 4;
const int task_field_gc_alloc_chain = 5;
const int task_field_dom = 6;
const int n_visible_task_fields = 7;

const int dom_field_interrupt_flag = 1;

const int frame_glue_fns_field_mark = 0;
const int frame_glue_fns_field_drop = 1;
const int frame_glue_fns_field_reloc = 2;

const int box_rc_field_refcnt = 0;
const int box_rc_field_body = 1;

const int general_code_alignment = 16;

const int vec_elt_rc = 0;
const int vec_elt_alloc = 1;
const int vec_elt_fill = 2;
const int vec_elt_pad = 3;
const int vec_elt_data = 4;

const int tydesc_field_first_param = 0;
const int tydesc_field_size = 1;
const int tydesc_field_align = 2;
const int tydesc_field_take_glue = 3;
const int tydesc_field_drop_glue = 4;
const int tydesc_field_free_glue = 5;
const int tydesc_field_sever_glue = 6;
const int tydesc_field_mark_glue = 7;
// FIXME no longer used in rustc, drop when rustboot is gone
const int tydesc_field_obj_drop_glue = 8;
const int tydesc_field_is_stateful = 9;
const int tydesc_field_cmp_glue = 10;
const int n_tydesc_fields = 11;

const uint cmp_glue_op_eq = 0u;
const uint cmp_glue_op_lt = 1u;
const uint cmp_glue_op_le = 2u;

const int obj_field_vtbl = 0;
const int obj_field_box = 1;

const int obj_body_elt_tydesc = 0;
const int obj_body_elt_typarams = 1;
const int obj_body_elt_fields = 2;

const int fn_field_code = 0;
const int fn_field_box = 1;

const int closure_elt_tydesc = 0;
const int closure_elt_target = 1;
const int closure_elt_bindings = 2;
const int closure_elt_ty_params = 3;

const int worst_case_glue_call_args = 7;

const int n_native_glues = 7;

const int abi_x86_rustboot_cdecl = 1;
const int abi_x86_rustc_fastcall = 2;

tag native_glue_type {
    ngt_rust;
    ngt_pure_rust;
    ngt_cdecl;
}

fn memcpy_glue_name() -> str {
    ret "rust_memcpy_glue";
}

fn bzero_glue_name() -> str {
    ret "rust_bzero_glue";
}

fn vec_append_glue_name() -> str {
    ret "rust_vec_append_glue";
}

fn native_glue_name(int n, native_glue_type ngt) -> str {
    auto prefix;
    alt (ngt) {
        case (ngt_rust)         { prefix = "rust_native_rust_"; }
        case (ngt_pure_rust)    { prefix = "rust_native_pure_rust_"; }
        case (ngt_cdecl)        { prefix = "rust_native_cdecl_"; }
    }
    ret prefix + util.common.istr(n);
}

fn activate_glue_name() -> str {
    ret "rust_activate_glue";
}

fn yield_glue_name() -> str {
    ret "rust_yield_glue";
}

fn exit_task_glue_name() -> str {
    ret "rust_exit_task_glue";
}

fn no_op_type_glue_name() -> str {
    ret "rust_no_op_type_glue";
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>rustc: Bump the number of native glues to 8<commit_after>// FIXME: Most of these should be uints.

const int rc_base_field_refcnt = 0;

// FIXME: import from std.dbg when imported consts work.
const uint const_refcount = 0x7bad_face_u;

const int task_field_refcnt = 0;
const int task_field_stk = 2;
const int task_field_runtime_sp = 3;
const int task_field_rust_sp = 4;
const int task_field_gc_alloc_chain = 5;
const int task_field_dom = 6;
const int n_visible_task_fields = 7;

const int dom_field_interrupt_flag = 1;

const int frame_glue_fns_field_mark = 0;
const int frame_glue_fns_field_drop = 1;
const int frame_glue_fns_field_reloc = 2;

const int box_rc_field_refcnt = 0;
const int box_rc_field_body = 1;

const int general_code_alignment = 16;

const int vec_elt_rc = 0;
const int vec_elt_alloc = 1;
const int vec_elt_fill = 2;
const int vec_elt_pad = 3;
const int vec_elt_data = 4;

const int tydesc_field_first_param = 0;
const int tydesc_field_size = 1;
const int tydesc_field_align = 2;
const int tydesc_field_take_glue = 3;
const int tydesc_field_drop_glue = 4;
const int tydesc_field_free_glue = 5;
const int tydesc_field_sever_glue = 6;
const int tydesc_field_mark_glue = 7;
// FIXME no longer used in rustc, drop when rustboot is gone
const int tydesc_field_obj_drop_glue = 8;
const int tydesc_field_is_stateful = 9;
const int tydesc_field_cmp_glue = 10;
const int n_tydesc_fields = 11;

const uint cmp_glue_op_eq = 0u;
const uint cmp_glue_op_lt = 1u;
const uint cmp_glue_op_le = 2u;

const int obj_field_vtbl = 0;
const int obj_field_box = 1;

const int obj_body_elt_tydesc = 0;
const int obj_body_elt_typarams = 1;
const int obj_body_elt_fields = 2;

const int fn_field_code = 0;
const int fn_field_box = 1;

const int closure_elt_tydesc = 0;
const int closure_elt_target = 1;
const int closure_elt_bindings = 2;
const int closure_elt_ty_params = 3;

const int worst_case_glue_call_args = 7;

const int n_native_glues = 8;

const int abi_x86_rustboot_cdecl = 1;
const int abi_x86_rustc_fastcall = 2;

tag native_glue_type {
    ngt_rust;
    ngt_pure_rust;
    ngt_cdecl;
}

fn memcpy_glue_name() -> str {
    ret "rust_memcpy_glue";
}

fn bzero_glue_name() -> str {
    ret "rust_bzero_glue";
}

fn vec_append_glue_name() -> str {
    ret "rust_vec_append_glue";
}

fn native_glue_name(int n, native_glue_type ngt) -> str {
    auto prefix;
    alt (ngt) {
        case (ngt_rust)         { prefix = "rust_native_rust_"; }
        case (ngt_pure_rust)    { prefix = "rust_native_pure_rust_"; }
        case (ngt_cdecl)        { prefix = "rust_native_cdecl_"; }
    }
    ret prefix + util.common.istr(n);
}

fn activate_glue_name() -> str {
    ret "rust_activate_glue";
}

fn yield_glue_name() -> str {
    ret "rust_yield_glue";
}

fn exit_task_glue_name() -> str {
    ret "rust_exit_task_glue";
}

fn no_op_type_glue_name() -> str {
    ret "rust_no_op_type_glue";
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>use toml:: { Parser };
use std::default:: { Default };
use std::path:: { Path };
use std::fs::File;
use std::io:: { Read };
use std::str:: { from_utf8 };
//let mut f = try!(File::create("foo.txt"));
//try!(f.write_all(b"Hello, world!"));

pub struct Configuration {
    host: String,
    port: String
}
/*
impl Configuration {
    pub fn fromFile(path: Path) -> Self {

        let mut f = try!(File::open("foo.txt"));
        let mut s = String::new();
        f.read_to_string(s);

        match from_utf8(s.as_bytes()) {
            Ok(v) => {
                let mut parser = Parser::new(v);
                match parser.parse() {
                    Some(table) => {
                        let host = table.get(&"host").unwrap();
                        let port = table.get(&"port").unwrap();

                        Configuration {
                            host: host.to_string(),
                            port: port.to_string()
                        }
                    },
                    None => println!("parse errors: {:?}", parser.errors)
                };
            },
            Err(err) => println!("{}", err)
        };

//        Configuration { host: "127.0.0.1".to_string(), port: "6767".to_string() }
    }
}

*/

impl Default for Configuration {
    fn default() -> Self {
        Configuration {
            host: "127.0.0.1".to_string(),
            port: "6767".to_string()
        }
    }
}

/*
pub fn loadconfig() {
    let mut parser = Parser::new(toml);
    match parser.parse() {
        Some(value) => println!("found toml: {:?}", value),
        None => {
            println!("parse errors: {:?}", parser.errors);
        }
    }
}
*/
<commit_msg>add read toml file<commit_after>use toml:: { Parser };
use std::default:: { Default };
use std::path:: { Path };
use std::fs::File;
use std::io:: { Read, Result };
use std::io;

pub struct Configuration {
    host: String,
    port: String
}
/*
impl Configuration {
    pub fn fromFile(path: Path) -> Self {

        let mut f = try!(File::open("foo.txt"));
        let mut s = String::new();
        f.read_to_string(s);

        match from_utf8(s.as_bytes()) {
            Ok(v) => {
                let mut parser = Parser::new(v);
                match parser.parse() {
                    Some(table) => {
                        let host = table.get(&"host").unwrap();
                        let port = table.get(&"port").unwrap();

                        Configuration {
                            host: host.to_string(),
                            port: port.to_string()
                        }
                    },
                    None => println!("parse errors: {:?}", parser.errors)
                };
            },
            Err(err) => println!("{}", err)
        };

//        Configuration { host: "127.0.0.1".to_string(), port: "6767".to_string() }
    }
}

*/

impl Default for Configuration {
    fn default() -> Self {
        Configuration {
            host: "127.0.0.1".to_string(),
            port: "6767".to_string()
        }
    }
}

fn readTomlFile(path: &Path) -> Result<String> {
    let mut file = try!(File::open(path));
    let mut buffer = String::new();
    let _ = try!(file.read_to_string(&mut buffer));
    Ok(content.clone())
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use conn::Conn;
use conn::futures::Disconnect;
use conn::futures::DropResult;
use conn::futures::NewConn;
use errors::*;
use lib_futures::Async;
use lib_futures::Async::Ready;
use lib_futures::Async::NotReady;
use lib_futures::Future;
use std::fmt;
use opts::Opts;
use self::futures::*;
use std::cell::Ref;
use std::cell::RefCell;
use std::cell::RefMut;
use std::rc::Rc;
use tokio::reactor::Handle;

pub mod futures;

pub struct Inner {
    closed: bool,
    new: Vec<NewConn>,
    idle: Vec<Conn>,
    disconnecting: Vec<Disconnect>,
    dropping: Vec<DropResult>,
}

#[derive(Clone)]
/// Asynchronous pool of MySql connections.
pub struct Pool {
    handle: Handle,
    opts: Opts,
    inner: Rc<RefCell<Inner>>,
    min: usize,
    max: usize,
}

impl fmt::Debug for Pool {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Pool")
         .field("min", &self.min)
         .field("max", &self.max)
         .field("new connections count", &self.inner_ref().new.len())
         .field("idle connections count", &self.inner_ref().idle.len())
         .field("disconnecting connections count", &self.inner_ref().disconnecting.len())
         .finish()
    }
}

impl Pool {
    /// Creates new pool of connections.
    pub fn new<O: Into<Opts>>(opts: O, handle: &Handle) -> Pool {
        let opts = opts.into();
        let pool_min = opts.get_pool_min();
        let pool_max = opts.get_pool_max();
        let mut new_conns = Vec::with_capacity(pool_min);
        for _ in 0..pool_min {
            let new_conn = Conn::new(opts.clone(), handle);
            new_conns.push(new_conn);
        }
        let pool = Pool {
            handle: handle.clone(),
            opts: opts,
            inner: Rc::new(RefCell::new(Inner {
                closed: false,
                new: new_conns,
                idle: Vec::new(),
                disconnecting: Vec::new(),
                dropping: Vec::new(),
            })),
            min: pool_min,
            max: pool_max,
        };

        pool
    }

    /// Returns future that resolves to `Conn`.
    pub fn get_conn(&self) -> GetConn {
        new_get_conn(self)
    }

    /// Returns future that disconnects this pool from server and resolves to `()`.
    ///
    /// Active connections taken from this pool should be disconnected manually.
    /// Also all pending and new `GetConn`'s will resolve to error.
    pub fn disconnect(mut self) -> DisconnectPool {
        if ! self.inner_ref().closed {
            self.inner_mut().closed = true;
            while let Some(conn) = self.take_conn() {
                self.inner_mut().disconnecting.push(conn.disconnect());
            }
        }
        new_disconnect_pool(self)
    }

    /// A way to take connection from a pool.
    fn take_conn(&mut self) -> Option<Conn> {
        let maybe_conn = self.inner_mut().idle.pop();
        maybe_conn.map(|mut conn| {
            // TODO: Add some kind of health check
            // TODO: Execute init after reconnect
            conn.pool = Some(self.clone());
            conn
        })
    }

    /// A way to return connection taken from a pool.
    fn return_conn(&mut self, conn: Conn) {
        if self.inner_ref().closed {
            return;
        }
        if conn.has_result.is_some() {
            self.inner_mut().dropping.push(conn.drop_result());
        } else {
            if self.inner_ref().idle.len() >= self.min {
                self.inner_mut().disconnecting.push(conn.disconnect());
            } else {
                self.inner_mut().idle.push(conn);
            }
        }
    }

    fn inner_ref(&self) -> Ref<Inner> {
        self.inner.borrow()
    }

    fn inner_mut(&mut self) -> RefMut<Inner> {
        self.inner.borrow_mut()
    }

    /// Will manage lifetime of futures stored in a pool.
    fn handle_futures(&mut self) -> Result<()> {
        macro_rules! handle {
            ($vec:ident { $($p:pat => $b:block,)+ }) => ({
                let len = self.inner_ref().$vec.len();
                let mut done_fut_idxs = Vec::new();
                for i in 0..len {
                    let result = self.inner_mut().$vec.get_mut(i).unwrap().poll();
                    if let Ok(Ready(_)) = result {
                        done_fut_idxs.push(i);
                    }
                    match result {
                        $($p => $b),+
                        _ => (),
                    }
                }
                while let Some(i) = done_fut_idxs.pop() {
                    self.inner_mut().$vec.swap_remove(i);
                }
            });
        }

        let mut handled = false;

        // Handle closing connections.
        handle!(disconnecting {
            Ok(Ready(_)) => {},
            Err(_) => {},
        });

        // Handle dirty connections.
        handle!(dropping {
            Ok(Ready(conn)) => {
                if self.inner_ref().closed {
                    self.inner_mut().disconnecting.push(conn.disconnect());
                } else {
                    self.return_conn(conn);
                }
                handled = true;
            },
            Err(_) => {},
        });

        // Handle connecting connections.
        handle!(new {
            Ok(Ready(conn)) => {
                if self.inner_ref().closed {
                    self.inner_mut().disconnecting.push(conn.disconnect());
                } else {
                    self.return_conn(conn);
                }
                handled = true;
            },
            Err(err) => {
                if ! self.inner_ref().closed {
                    return Err(err);
                }
            },
        });

        if handled {
            self.handle_futures()
        } else {
            Ok(())
        }
    }

    /// Will poll pool for connection.
    fn poll(&mut self) -> Result<Async<Conn>> {
        if self.inner_ref().closed {
            return Err(ErrorKind::PoolDisconnected.into());
        }

        try!(self.handle_futures());

        match self.take_conn() {
            Some(conn) => Ok(Ready(conn)),
            None => if self.inner_ref().new.len() == 0 && self.inner_ref().idle.len() < self.max {
                let new_conn = Conn::new(self.opts.clone(), &self.handle);
                self.inner_mut().new.push(new_conn);
                self.poll()
            } else {
                Ok(NotReady)
            }
        }
    }
}

impl Drop for Conn {
    fn drop(&mut self) {
        if let Some(mut pool) = self.pool.take() {
            let conn = self.take();
            pool.return_conn(conn)
        }
    }
}

#[cfg(test)]
mod test {
    use conn::pool::Pool;
    use lib_futures::Future;
    use test_misc::DATABASE_URL;
    use tokio::reactor::Core;

    #[test]
    fn should_connect() {
        let mut lp = Core::new().unwrap();

        let pool = Pool::new(&**DATABASE_URL, &lp.handle());
        let fut = pool.get_conn().and_then(|conn| conn.ping().map(|_| ())).and_then(|_| {
            pool.disconnect()
        });

        lp.run(fut).unwrap();
    }

    #[test]
    fn should_hold_bounds() {
        let mut lp = Core::new().unwrap();

        let pool = Pool::new(format!("{}?pool_min=1&pool_max=2", &**DATABASE_URL), &lp.handle());
        let pool_clone = pool.clone();
        let fut = pool.get_conn().join(pool.get_conn()).and_then(|(mut conn1, conn2)| {
            let new_conn = pool_clone.get_conn();
            conn1.pool.as_mut().unwrap().handle_futures().unwrap();
            assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().new.len(), 0);
            assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().idle.len(), 0);
            assert_eq!(conn2.pool.as_ref().unwrap().inner_ref().disconnecting.len(), 0);
            assert_eq!(conn2.pool.as_ref().unwrap().inner_ref().dropping.len(), 0);
            new_conn
        }).and_then(|conn1| {
            assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().new.len(), 0);
            assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().idle.len(), 0);
            assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().disconnecting.len(), 0);
            assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().dropping.len(), 0);
            Ok(())
        }).and_then(|_| {
            assert_eq!(pool.inner_ref().new.len(), 0);
            assert_eq!(pool.inner_ref().idle.len(), 1);
            assert_eq!(pool.inner_ref().disconnecting.len(), 0);
            assert_eq!(pool.inner_ref().dropping.len(), 0);
            pool.disconnect()
        });

        lp.run(fut).unwrap();
    }

    #[cfg(feature = "nightly")]
    mod bench {
        use test;
        use conn::pool::Pool;
        use tokio::reactor::Core;
        use lib_futures::Future;
        use test_misc::DATABASE_URL;

        #[bench]
        fn connect(bencher: &mut test::Bencher) {
            let mut lp = Core::new().unwrap();
            let pool = Pool::new(&**DATABASE_URL, &lp.handle());

            bencher.iter(|| {
                let fut = pool.get_conn().and_then(|conn| { conn.ping() });
                lp.run(fut).unwrap();
            })
        }
    }
}
<commit_msg>Workaround borrow checker<commit_after>// Copyright (c) 2016 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use conn::Conn;
use conn::futures::Disconnect;
use conn::futures::DropResult;
use conn::futures::NewConn;
use errors::*;
use lib_futures::Async;
use lib_futures::Async::Ready;
use lib_futures::Async::NotReady;
use lib_futures::Future;
use std::fmt;
use opts::Opts;
use self::futures::*;
use std::cell::Ref;
use std::cell::RefCell;
use std::cell::RefMut;
use std::rc::Rc;
use tokio::reactor::Handle;

pub mod futures;

pub struct Inner {
    closed: bool,
    new: Vec<NewConn>,
    idle: Vec<Conn>,
    disconnecting: Vec<Disconnect>,
    dropping: Vec<DropResult>,
}

#[derive(Clone)]
/// Asynchronous pool of MySql connections.
pub struct Pool {
    handle: Handle,
    opts: Opts,
    inner: Rc<RefCell<Inner>>,
    min: usize,
    max: usize,
}

impl fmt::Debug for Pool {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Pool")
         .field("min", &self.min)
         .field("max", &self.max)
         .field("new connections count", &self.inner_ref().new.len())
         .field("idle connections count", &self.inner_ref().idle.len())
         .field("disconnecting connections count", &self.inner_ref().disconnecting.len())
         .finish()
    }
}

impl Pool {
    /// Creates new pool of connections.
    pub fn new<O: Into<Opts>>(opts: O, handle: &Handle) -> Pool {
        let opts = opts.into();
        let pool_min = opts.get_pool_min();
        let pool_max = opts.get_pool_max();
        let mut new_conns = Vec::with_capacity(pool_min);
        for _ in 0..pool_min {
            let new_conn = Conn::new(opts.clone(), handle);
            new_conns.push(new_conn);
        }
        let pool = Pool {
            handle: handle.clone(),
            opts: opts,
            inner: Rc::new(RefCell::new(Inner {
                closed: false,
                new: new_conns,
                idle: Vec::new(),
                disconnecting: Vec::new(),
                dropping: Vec::new(),
            })),
            min: pool_min,
            max: pool_max,
        };

        pool
    }

    /// Returns future that resolves to `Conn`.
    pub fn get_conn(&self) -> GetConn {
        new_get_conn(self)
    }

    /// Returns future that disconnects this pool from server and resolves to `()`.
    ///
    /// Active connections taken from this pool should be disconnected manually.
    /// Also all pending and new `GetConn`'s will resolve to error.
    pub fn disconnect(mut self) -> DisconnectPool {
        if ! self.inner_ref().closed {
            self.inner_mut().closed = true;
            while let Some(conn) = self.take_conn() {
                self.inner_mut().disconnecting.push(conn.disconnect());
            }
        }
        new_disconnect_pool(self)
    }

    /// A way to take connection from a pool.
    fn take_conn(&mut self) -> Option<Conn> {
        let maybe_conn = self.inner_mut().idle.pop();
        maybe_conn.map(|mut conn| {
            // TODO: Add some kind of health check
            // TODO: Execute init after reconnect
            conn.pool = Some(self.clone());
            conn
        })
    }

    /// A way to return connection taken from a pool.
    fn return_conn(&mut self, conn: Conn) {
        if self.inner_ref().closed {
            return;
        }
        if conn.has_result.is_some() {
            self.inner_mut().dropping.push(conn.drop_result());
        } else {
            let idle_len = self.inner_ref().idle.len();
            if idle_len >= self.min {
                self.inner_mut().disconnecting.push(conn.disconnect());
            } else {
                self.inner_mut().idle.push(conn);
            }
        }
    }

    fn inner_ref(&self) -> Ref<Inner> {
        self.inner.borrow()
    }

    fn inner_mut(&mut self) -> RefMut<Inner> {
        self.inner.borrow_mut()
    }

    /// Will manage lifetime of futures stored in a pool.
    fn handle_futures(&mut self) -> Result<()> {
        macro_rules! handle {
            ($vec:ident { $($p:pat => $b:block,)+ }) => ({
                let len = self.inner_ref().$vec.len();
                let mut done_fut_idxs = Vec::new();
                for i in 0..len {
                    let result = self.inner_mut().$vec.get_mut(i).unwrap().poll();
                    if let Ok(Ready(_)) = result {
                        done_fut_idxs.push(i);
                    }
                    match result {
                        $($p => $b),+
                        _ => (),
                    }
                }
                while let Some(i) = done_fut_idxs.pop() {
                    self.inner_mut().$vec.swap_remove(i);
                }
            });
        }

        let mut handled = false;

        // Handle closing connections.
        handle!(disconnecting {
            Ok(Ready(_)) => {},
            Err(_) => {},
        });

        // Handle dirty connections.
        handle!(dropping {
            Ok(Ready(conn)) => {
                let closed = self.inner_ref().closed;
                if closed {
                    self.inner_mut().disconnecting.push(conn.disconnect());
                } else {
                    self.return_conn(conn);
                }
                handled = true;
            },
            Err(_) => {},
        });

        // Handle connecting connections.
        handle!(new {
            Ok(Ready(conn)) => {
                let closed = self.inner_ref().closed;
                if closed {
                    self.inner_mut().disconnecting.push(conn.disconnect());
                } else {
                    self.return_conn(conn);
                }
                handled = true;
            },
            Err(err) => {
                if ! self.inner_ref().closed {
                    return Err(err);
                }
            },
        });

        if handled {
            self.handle_futures()
        } else {
            Ok(())
        }
    }

    /// Will poll pool for connection.
    fn poll(&mut self) -> Result<Async<Conn>> {
        if self.inner_ref().closed {
            return Err(ErrorKind::PoolDisconnected.into());
        }

        try!(self.handle_futures());

        match self.take_conn() {
            Some(conn) => Ok(Ready(conn)),
            None => {
                let new_len = self.inner_ref().new.len();
                let idle_len = self.inner_ref().idle.len();
                if new_len == 0 && idle_len < self.max {
                    let new_conn = Conn::new(self.opts.clone(), &self.handle);
                    self.inner_mut().new.push(new_conn);
                    self.poll()
                } else {
                    Ok(NotReady)
                }
            },
        }
    }
}

impl Drop for Conn {
    fn drop(&mut self) {
        if let Some(mut pool) = self.pool.take() {
            let conn = self.take();
            pool.return_conn(conn)
        }
    }
}

#[cfg(test)]
mod test {
    use conn::pool::Pool;
    use lib_futures::Future;
    use test_misc::DATABASE_URL;
    use tokio::reactor::Core;

    #[test]
    fn should_connect() {
        let mut lp = Core::new().unwrap();

        let pool = Pool::new(&**DATABASE_URL, &lp.handle());
        let fut = pool.get_conn().and_then(|conn| conn.ping().map(|_| ())).and_then(|_| {
            pool.disconnect()
        });

        lp.run(fut).unwrap();
    }

    #[test]
    fn should_hold_bounds() {
        let mut lp = Core::new().unwrap();

        let pool = Pool::new(format!("{}?pool_min=1&pool_max=2", &**DATABASE_URL), &lp.handle());
        let pool_clone = pool.clone();
        let fut = pool.get_conn().join(pool.get_conn()).and_then(|(mut conn1, conn2)| {
            let new_conn = pool_clone.get_conn();
            conn1.pool.as_mut().unwrap().handle_futures().unwrap();
            assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().new.len(), 0);
            assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().idle.len(), 0);
            assert_eq!(conn2.pool.as_ref().unwrap().inner_ref().disconnecting.len(), 0);
            assert_eq!(conn2.pool.as_ref().unwrap().inner_ref().dropping.len(), 0);
            new_conn
        }).and_then(|conn1| {
            assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().new.len(), 0);
            assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().idle.len(), 0);
            assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().disconnecting.len(), 0);
            assert_eq!(conn1.pool.as_ref().unwrap().inner_ref().dropping.len(), 0);
            Ok(())
        }).and_then(|_| {
            assert_eq!(pool.inner_ref().new.len(), 0);
            assert_eq!(pool.inner_ref().idle.len(), 1);
            assert_eq!(pool.inner_ref().disconnecting.len(), 0);
            assert_eq!(pool.inner_ref().dropping.len(), 0);
            pool.disconnect()
        });

        lp.run(fut).unwrap();
    }

    #[cfg(feature = "nightly")]
    mod bench {
        use test;
        use conn::pool::Pool;
        use tokio::reactor::Core;
        use lib_futures::Future;
        use test_misc::DATABASE_URL;

        #[bench]
        fn connect(bencher: &mut test::Bencher) {
            let mut lp = Core::new().unwrap();
            let pool = Pool::new(&**DATABASE_URL, &lp.handle());

            bencher.iter(|| {
                let fut = pool.get_conn().and_then(|conn| { conn.ping() });
                lp.run(fut).unwrap();
            })
        }
    }
}
<|endoftext|>