<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![deny(unsafe_code)]

#![crate_name = "servo_url"]
#![crate_type = "rlib"]

#![cfg_attr(feature = "servo", feature(plugin))]
#![cfg_attr(feature = "servo", feature(proc_macro))]

#[cfg(feature = "servo")] extern crate serde;
#[cfg(feature = "servo")] #[macro_use] extern crate serde_derive;
#[cfg(feature = "servo")] extern crate heapsize;
#[cfg(feature = "servo")] #[macro_use] extern crate heapsize_derive;

extern crate url;

use std::fmt;
use std::net::IpAddr;
use std::ops::{Range, RangeFrom, RangeTo, RangeFull, Index};
use std::path::Path;
use std::sync::Arc;
use url::{Url, Origin, Position};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Serialize, Deserialize))]
pub struct ServoUrl(Arc<Url>);

impl ServoUrl {
    pub fn from_url(url: Url) -> Self {
        ServoUrl(Arc::new(url))
    }

    pub fn parse_with_base(base: Option<&Self>, input: &str) -> Result<Self, url::ParseError> {
        Url::options().base_url(base.map(|b| &*b.0)).parse(input).map(Self::from_url)
    }

    pub fn into_string(self) -> String {
        Arc::try_unwrap(self.0).unwrap_or_else(|s| (*s).clone()).into_string()
    }

    // NOTE: These methods return options that are always true temporarily until
    // we special-case some urls to avoid going through rust-url.
    pub fn into_url(self) -> Option<Url> {
        Some(Arc::try_unwrap(self.0).unwrap_or_else(|s| (*s).clone()))
    }

    pub fn as_url(&self) -> Option<&Arc<Url>> {
        Some(&self.0)
    }

    pub fn parse(input: &str) -> Result<Self, url::ParseError> {
        Url::parse(input).map(Self::from_url)
    }

    pub fn cannot_be_a_base(&self) -> bool {
        self.0.cannot_be_a_base()
    }

    pub fn domain(&self) -> Option<&str> {
        self.0.domain()
    }

    pub fn fragment(&self) -> Option<&str> {
        self.0.fragment()
    }

    pub fn path(&self) -> &str {
        self.0.path()
    }

    pub fn origin(&self) -> Origin {
        self.0.origin()
    }

    pub fn scheme(&self) -> &str {
        self.0.scheme()
    }

    pub fn as_str(&self) -> &str {
        self.0.as_str()
    }

    pub fn as_mut_url(&mut self) -> Option<&mut Url> {
        Some(Arc::make_mut(&mut self.0))
    }

    pub fn set_username(&mut self, user: &str) -> Result<(), ()> {
        Arc::make_mut(&mut self.0).set_username(user)
    }

    pub fn set_ip_host(&mut self, addr: IpAddr) -> Result<(), ()> {
        Arc::make_mut(&mut self.0).set_ip_host(addr)
    }

    pub fn set_password(&mut self, pass: Option<&str>) -> Result<(), ()> {
        Arc::make_mut(&mut self.0).set_password(pass)
    }

    pub fn set_fragment(&mut self, fragment: Option<&str>) {
        Arc::make_mut(&mut self.0).set_fragment(fragment)
    }

    pub fn username(&self) -> &str {
        self.0.username()
    }

    pub fn password(&self) -> Option<&str> {
        self.0.password()
    }

    pub fn to_file_path(&self) -> Result<::std::path::PathBuf, ()> {
        self.0.to_file_path()
    }

    pub fn host(&self) -> Option<url::Host<&str>> {
        self.0.host()
    }

    pub fn host_str(&self) -> Option<&str> {
        self.0.host_str()
    }

    pub fn port(&self) -> Option<u16> {
        self.0.port()
    }

    pub fn port_or_known_default(&self) -> Option<u16> {
        self.0.port_or_known_default()
    }

    pub fn join(&self, input: &str) -> Result<ServoUrl, url::ParseError> {
        self.0.join(input).map(Self::from_url)
    }

    pub fn path_segments(&self) -> Option<::std::str::Split<char>> {
        self.0.path_segments()
    }

    pub fn query(&self) -> Option<&str> {
        self.0.query()
    }

    pub fn from_file_path<P: AsRef<Path>>(path: P) -> Result<Self, ()> {
        Ok(Self::from_url(try!(Url::from_file_path(path))))
    }
}

impl fmt::Display for ServoUrl {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(formatter)
    }
}

impl Index<RangeFull> for ServoUrl {
    type Output = str;
    fn index(&self, _: RangeFull) -> &str {
        &self.0[..]
    }
}

impl Index<RangeFrom<Position>> for ServoUrl {
    type Output = str;
    fn index(&self, range: RangeFrom<Position>) -> &str {
        &self.0[range]
    }
}

impl Index<RangeTo<Position>> for ServoUrl {
    type Output = str;
    fn index(&self, range: RangeTo<Position>) -> &str {
        &self.0[range]
    }
}

impl Index<Range<Position>> for ServoUrl {
    type Output = str;
    fn index(&self, range: Range<Position>) -> &str {
        &self.0[range]
    }
}
<commit_msg>Adds ServoUrl::is_secure_scheme helper<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![deny(unsafe_code)]

#![crate_name = "servo_url"]
#![crate_type = "rlib"]

#![cfg_attr(feature = "servo", feature(plugin))]
#![cfg_attr(feature = "servo", feature(proc_macro))]

#[cfg(feature = "servo")] extern crate serde;
#[cfg(feature = "servo")] #[macro_use] extern crate serde_derive;
#[cfg(feature = "servo")] extern crate heapsize;
#[cfg(feature = "servo")] #[macro_use] extern crate heapsize_derive;

extern crate url;

use std::fmt;
use std::net::IpAddr;
use std::ops::{Range, RangeFrom, RangeTo, RangeFull, Index};
use std::path::Path;
use std::sync::Arc;
use url::{Url, Origin, Position};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Serialize, Deserialize))]
pub struct ServoUrl(Arc<Url>);

impl ServoUrl {
    pub fn from_url(url: Url) -> Self {
        ServoUrl(Arc::new(url))
    }

    pub fn parse_with_base(base: Option<&Self>, input: &str) -> Result<Self, url::ParseError> {
        Url::options().base_url(base.map(|b| &*b.0)).parse(input).map(Self::from_url)
    }

    pub fn into_string(self) -> String {
        Arc::try_unwrap(self.0).unwrap_or_else(|s| (*s).clone()).into_string()
    }

    // NOTE: These methods return options that are always true temporarily until
    // we special-case some urls to avoid going through rust-url.
    pub fn into_url(self) -> Option<Url> {
        Some(Arc::try_unwrap(self.0).unwrap_or_else(|s| (*s).clone()))
    }

    pub fn as_url(&self) -> Option<&Arc<Url>> {
        Some(&self.0)
    }

    pub fn parse(input: &str) -> Result<Self, url::ParseError> {
        Url::parse(input).map(Self::from_url)
    }

    pub fn cannot_be_a_base(&self) -> bool {
        self.0.cannot_be_a_base()
    }

    pub fn domain(&self) -> Option<&str> {
        self.0.domain()
    }

    pub fn fragment(&self) -> Option<&str> {
        self.0.fragment()
    }

    pub fn path(&self) -> &str {
        self.0.path()
    }

    pub fn origin(&self) -> Origin {
        self.0.origin()
    }

    pub fn scheme(&self) -> &str {
        self.0.scheme()
    }

    pub fn is_secure_scheme(&self) -> bool {
        let scheme = self.scheme();
        scheme == "https" || scheme == "wss"
    }

    pub fn as_str(&self) -> &str {
        self.0.as_str()
    }

    pub fn as_mut_url(&mut self) -> Option<&mut Url> {
        Some(Arc::make_mut(&mut self.0))
    }

    pub fn set_username(&mut self, user: &str) -> Result<(), ()> {
        Arc::make_mut(&mut self.0).set_username(user)
    }

    pub fn set_ip_host(&mut self, addr: IpAddr) -> Result<(), ()> {
        Arc::make_mut(&mut self.0).set_ip_host(addr)
    }

    pub fn set_password(&mut self, pass: Option<&str>) -> Result<(), ()> {
        Arc::make_mut(&mut self.0).set_password(pass)
    }

    pub fn set_fragment(&mut self, fragment: Option<&str>) {
        Arc::make_mut(&mut self.0).set_fragment(fragment)
    }

    pub fn username(&self) -> &str {
        self.0.username()
    }

    pub fn password(&self) -> Option<&str> {
        self.0.password()
    }

    pub fn to_file_path(&self) -> Result<::std::path::PathBuf, ()> {
        self.0.to_file_path()
    }

    pub fn host(&self) -> Option<url::Host<&str>> {
        self.0.host()
    }

    pub fn host_str(&self) -> Option<&str> {
        self.0.host_str()
    }

    pub fn port(&self) -> Option<u16> {
        self.0.port()
    }

    pub fn port_or_known_default(&self) -> Option<u16> {
        self.0.port_or_known_default()
    }

    pub fn join(&self, input: &str) -> Result<ServoUrl, url::ParseError> {
        self.0.join(input).map(Self::from_url)
    }

    pub fn path_segments(&self) -> Option<::std::str::Split<char>> {
        self.0.path_segments()
    }

    pub fn query(&self) -> Option<&str> {
        self.0.query()
    }

    pub fn from_file_path<P: AsRef<Path>>(path: P) -> Result<Self, ()> {
        Ok(Self::from_url(try!(Url::from_file_path(path))))
    }
}

impl fmt::Display for ServoUrl {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(formatter)
    }
}

impl Index<RangeFull> for ServoUrl {
    type Output = str;
    fn index(&self, _: RangeFull) -> &str {
        &self.0[..]
    }
}

impl Index<RangeFrom<Position>> for ServoUrl {
    type Output = str;
    fn index(&self, range: RangeFrom<Position>) -> &str {
        &self.0[range]
    }
}

impl Index<RangeTo<Position>> for ServoUrl {
    type Output = str;
    fn index(&self, range: RangeTo<Position>) -> &str {
        &self.0[range]
    }
}

impl Index<Range<Position>> for ServoUrl {
    type Output = str;
    fn index(&self, range: Range<Position>) -> &str {
        &self.0[range]
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::ops::MulAssign;
use approx::ApproxEq;
use alga::linear::Transformation;
use alga::linear::ProjectiveTransformation;
use na::{self, DVector, Dim, Dynamic, Real, U1, Unit, VectorSliceMutN};
use ncollide::query::ContactKinematic;

use object::{BodyHandle, BodyPart, BodySet};
use solver::helper;
use solver::{ForceDirection, NonlinearNormalConeConstraint, NonlinearUnilateralConstraint};
use math::{Isometry, Point, Rotation, Vector};

struct ContactGeometry<N: Real> {
    world1: Point<N>,
    world2: Point<N>,
    normal1: Unit<Vector<N>>,
    normal2: Unit<Vector<N>>,
    normal: Unit<Vector<N>>,
    depth: N,
}

impl<N: Real> ContactGeometry<N> {
    pub fn new(
        world1: Point<N>,
        world2: Point<N>,
        normal1: Unit<Vector<N>>,
        normal2: Unit<Vector<N>>,
        normal: Unit<Vector<N>>,
        depth: N,
    ) -> Self {
        ContactGeometry {
            world1,
            world2,
            normal1,
            normal2,
            normal,
            depth,
        }
    }
}

pub struct NonlinearSORProx<N: Real> {
    _phantom: PhantomData<N>,
}

impl<N: Real> NonlinearSORProx<N> {
    pub fn new() -> Self {
        NonlinearSORProx {
            _phantom: PhantomData,
        }
    }

    pub fn solve(
        &self,
        bodies: &mut BodySet<N>,
        constraints: &mut [NonlinearUnilateralConstraint<N>],
        ncone_constraints: &mut [NonlinearNormalConeConstraint<N>],
        mj_lambda: &mut DVector<N>,
        jacobians: &mut [N],
        max_iter: usize,
    ) {
        for _ in 0..max_iter {
            for constraint in constraints.iter_mut() {
                // FIXME: specialize for SPATIAL_DIM.
                let dim1 = Dynamic::new(constraint.ndofs1);
                let dim2 = Dynamic::new(constraint.ndofs2);
                self.solve_unilateral(bodies, constraint, mj_lambda, jacobians, dim1, dim2);

                // self.solve_normal(
                //     bodies,
                //     constraint,
                //     &mut ncone_constraints[constraint.normal_constraint_id],
                //     mj_lambda,
                //     jacobians,
                //     dim1,
                //     dim2,
                // );
            }
        }
    }

    fn solve_unilateral<D1: Dim, D2: Dim>(
        &self,
        bodies: &mut BodySet<N>,
        constraint: &mut NonlinearUnilateralConstraint<N>,
        mj_lambda: &mut DVector<N>,
        jacobians: &mut [N],
        dim1: D1,
        dim2: D2,
    ) {
        self.update_contact_constraint(bodies, constraint, jacobians);

        let impulse = -constraint.rhs / constraint.inv_r;

        if impulse > N::zero() {
            VectorSliceMutN::new_generic_mut(jacobians, dim1, U1).mul_assign(impulse);
            VectorSliceMutN::new_generic_mut(&mut jacobians[dim1.value()..], dim2, U1)
                .mul_assign(impulse);

            bodies
                .body_mut(constraint.body1)
                .apply_displacement(&jacobians[0..dim1.value()]);
            bodies
                .body_mut(constraint.body2)
                .apply_displacement(&jacobians[dim1.value()..dim1.value() + dim2.value()]);
        }
    }

    fn solve_normal<D1: Dim, D2: Dim>(
        &self,
        bodies: &mut BodySet<N>,
        contact: &NonlinearUnilateralConstraint<N>,
        constraint: &mut NonlinearNormalConeConstraint<N>,
        mj_lambda: &mut DVector<N>,
        jacobians: &mut [N],
        dim1: D1,
        dim2: D2,
    ) {
        if self.update_normal_cone_constraint(bodies, contact, constraint, jacobians) {
            let impulse = -constraint.rhs / constraint.inv_r;

            VectorSliceMutN::new_generic_mut(jacobians, dim1, U1).mul_assign(impulse);
            VectorSliceMutN::new_generic_mut(&mut jacobians[dim1.value()..], dim2, U1)
                .mul_assign(impulse);

            bodies
                .body_mut(contact.body1)
                .apply_displacement(&jacobians[0..dim1.value()]);
            bodies
                .body_mut(contact.body2)
                .apply_displacement(&jacobians[dim1.value()..dim1.value() + dim2.value()]);
        }
    }

    fn compute_contact_geometry(
        &self,
        body1: &BodyPart<N>,
        body2: &BodyPart<N>,
        constraint: &NonlinearUnilateralConstraint<N>,
    ) -> ContactGeometry<N> {
        let m1 = body1.position();
        let m2 = body2.position();

        let mut world1 = m1.transform_point(&constraint.local1);
        let mut world2 = m2.transform_point(&constraint.local2);
        let normal;
        let normal1;
        let normal2;
        let mut depth;

        match constraint.kinematic {
            ContactKinematic::PlanePoint => {
                normal = m1 * constraint.normal1;
                depth = -na::dot(normal.as_ref(), &(world2 - world1));
                world1 = world2 + normal.as_ref() * depth;
                normal1 = constraint.normal1;
                normal2 = -Unit::new_unchecked(m2.inverse_transform_vector(normal.as_ref()));
            }
            ContactKinematic::PointPlane => {
                let world_normal2 = m2 * constraint.normal2.as_ref();
                depth = -na::dot(&world_normal2, &(world1 - world2));
                world2 = world1 + &world_normal2 * depth;
                normal = Unit::new_unchecked(-world_normal2);
                normal1 = Unit::new_unchecked(m1.inverse_transform_vector(normal.as_ref()));
                normal2 = constraint.normal2;
            }
            ContactKinematic::PointPoint => {
                if let Some((n, d)) = Unit::try_new_and_get(world2 - world1, N::default_epsilon()) {
                    depth = -d;
                    normal = n;
                } else {
                    depth = -constraint.margin1 - constraint.margin2;
                    normal = m1 * constraint.normal1;
                }
                normal1 = Unit::new_unchecked(m1.inverse_transform_vector(normal.as_ref()));
                normal2 = -Unit::new_unchecked(m2.inverse_transform_vector(normal.as_ref()));
            }
            ContactKinematic::LinePoint(dir1) => {
                /*
                let mut shift = world2 - world1;
                let proj = na::dot(dir1.as_ref(), &shift);
                shift -= dir1.as_ref() * proj;
                world1 = world2 - shift;

                if let Some((n, d)) = Unit::try_new_and_get(shift, N::zero()) {
                    depth = d;
                    normal = n;
                } else {
                    depth = na::zero();
                    normal = Unit::new_unchecked(m1.transform_vector(constraint.normal1.as_ref()));
                }
                */
                unimplemented!()
            }
            ContactKinematic::PointLine(dir2) => {
                /*
                let mut shift = world1 - world2;
                let proj = na::dot(dir2.as_ref(), &shift);
                shift -= dir2.as_ref() * proj;
                world2 = world1 - shift;

                if let Some((n, d)) = Unit::try_new_and_get(shift, N::zero()) {
                    depth = d;
                    normal = n;
                } else {
                    depth = na::zero();
                    normal = Unit::new_unchecked(m1.transform_vector(constraint.normal1.as_ref()));
                }
                */
                unimplemented!()
            }
            ContactKinematic::LineLine(dir1, dir2) => {
                let world_dir1 = m1 * dir1;
                let world_dir2 = m2 * dir2;
                // let (pt1, pt2) = closest_points(world1, world_dir1, world2, world_dir2);
                // world1 = pt1;
                // world2 = pt2;

                if let Some((n, d)) = Unit::try_new_and_get(world2 - world1, N::zero()) {
                    let local_n1 = m1.inverse_transform_vector(n.as_ref());
                    let local_n2 = m2.inverse_transform_vector(&-*n);

                    if constraint.ncone1.contains(&local_n1)
                        && constraint.ncone2.contains(&local_n2)
                    {
                        depth = d;
                        normal = n;
                    } else {
                        depth = -d;
                        normal = -n;
                    }
                } else {
                    depth = na::zero();
                    normal = Unit::new_unchecked(m1.transform_vector(constraint.normal1.as_ref()));
                }

                normal1 = Unit::new_unchecked(m1.inverse_transform_vector(normal.as_ref()));
                normal2 = -Unit::new_unchecked(m2.inverse_transform_vector(normal.as_ref()));
            }
            ContactKinematic::Unknown => {
                depth = N::zero();
                normal = m1 * constraint.normal1;
                normal1 = constraint.normal1;
                normal2 = -Unit::new_unchecked(m2.inverse_transform_vector(normal.as_ref()));
            }
        }

        world1 += normal.unwrap() * constraint.margin1;
        world2 -= normal.unwrap() * constraint.margin2;
        depth += constraint.margin1 + constraint.margin2;

        ContactGeometry::new(world1, world2, normal1, normal2, normal, depth)
    }

    fn update_contact_constraint(
        &self,
        bodies: &BodySet<N>,
        constraint: &mut NonlinearUnilateralConstraint<N>,
        jacobians: &mut [N],
    ) {
        let body1 = bodies.body_part(constraint.body1);
        let body2 = bodies.body_part(constraint.body2);

        let geom = self.compute_contact_geometry(&body1, &body2, constraint);

        let erp: N = na::convert(0.2); // XXX: don't hard-code this.s
        let allowed_error: N = na::convert(0.005); // XXX don't hard-code this.
        let max_correction: N = na::convert(0.2); // XXX don't hard-code this.
        constraint.rhs = na::sup(&(-geom.depth * erp), &(-max_correction)) + allowed_error;

        constraint.inv_r = N::zero();
        helper::fill_constraint_geometry(
            &body1,
            constraint.ndofs1,
            &geom.world1,
            &ForceDirection::Linear(-geom.normal),
            constraint.ndofs1 + constraint.ndofs2,
            0,
            jacobians,
            &mut constraint.inv_r,
        );

        helper::fill_constraint_geometry(
            &body2,
            constraint.ndofs2,
            &geom.world2,
            &ForceDirection::Linear(geom.normal),
            (constraint.ndofs1 * 2) + constraint.ndofs2,
            constraint.ndofs1,
            jacobians,
            &mut constraint.inv_r,
        );

        // May happen sometimes for self-collisions (e.g. a multibody with itself).
        if constraint.inv_r.is_zero() {
            constraint.inv_r = N::one();
        }
    }

    fn update_normal_cone_constraint(
        &self,
        bodies: &BodySet<N>,
        contact: &NonlinearUnilateralConstraint<N>,
        constraint: &mut NonlinearNormalConeConstraint<N>,
        jacobians: &mut [N],
    ) -> bool {
        if contact.rhs >= N::zero() {
            return false;
        }

        let body1 = bodies.body_part(contact.body1);
        let body2 = bodies.body_part(contact.body2);

        let geom = self.compute_contact_geometry(&body1, &body2, contact);

        let closest_n1 = constraint.ncone1.project(&geom.normal1);
        let closest_n2 = constraint.ncone2.project(&geom.normal2);

        // FIXME: could rot1 and rot2 be obtained as a by-product of the projection?
        let rot1;
        let rot2;

        #[cfg(feature = "dim3")]
        {
            // NOTE: we assume the case where both vectors are antipodal
            // (i.e. the result is None) happens too rarely to be handled properly.
            // So if it does, no correction will be made for this iteration.
            let id = Rotation::identity();
            rot1 = Rotation::rotation_between_axis(&geom.normal1, &closest_n1).unwrap_or(id);
            rot2 = Rotation::rotation_between_axis(&geom.normal2, &closest_n2).unwrap_or(id);
        }

        #[cfg(feature = "dim2")]
        {
            rot1 = Rotation::rotation_between_axis(&geom.normal1, &closest_n1);
            rot2 = Rotation::rotation_between_axis(&geom.normal2, &closest_n2);
        }

        let m1 = body1.position();
        let m2 = body2.position();

        let (axis, ang, m) = match (rot1.axis_angle(), rot2.axis_angle()) {
            (None, None) => {
                return false;
            }
            (Some((axis1, ang1)), None) => (axis1, ang1, &m1),
            (None, Some((axis2, ang2))) => (-axis2, ang2, &m2),
            (Some((axis1, ang1)), Some((axis2, ang2))) => {
                if ang1 > ang2 {
                    (axis1, ang1, &m1)
                } else {
                    (-axis2, ang2, &m2)
                }
            }
        };

        let world_axis;
        #[cfg(feature = "dim2")]
        {
            world_axis = axis;
        }

        #[cfg(feature = "dim3")]
        {
            world_axis = m * axis;
        }

        constraint.rhs = -ang; // na::sup(&-ang, &na::convert(-0.02));
                               // println!("Angular stabilization: {}", ang);
        if constraint.rhs >= N::zero() {
            return false;
        }

        // FIXME: for 2D rigid bodies, there is no need to recompute the
        // constraint geometry at each frame because the jacobians will
        // always be the same (except maybe for the sign).
        constraint.inv_r = N::zero();
        helper::fill_constraint_geometry(
            &body1,
            contact.ndofs1,
            &body1.center_of_mass(),
            &ForceDirection::Angular(world_axis),
            contact.ndofs1 + contact.ndofs2,
            0,
            jacobians,
            &mut constraint.inv_r,
        );

        helper::fill_constraint_geometry(
            &body2,
            contact.ndofs2,
            &body2.center_of_mass(),
            &ForceDirection::Angular(-world_axis),
            (contact.ndofs1 * 2) + contact.ndofs2,
            contact.ndofs1,
            jacobians,
            &mut constraint.inv_r,
        );

        // May happen sometimes for self-collisions (e.g. a multibody with itself).
        if constraint.inv_r.is_zero() {
            constraint.inv_r = N::one();
        }

        return true;
    }
}
<commit_msg>Fix update of line-line contact kinematic.<commit_after>use std::marker::PhantomData;
use std::ops::MulAssign;
use approx::ApproxEq;
use alga::linear::Transformation;
use alga::linear::ProjectiveTransformation;
use na::{self, DVector, Dim, Dynamic, Real, U1, Unit, VectorSliceMutN};
use ncollide::query::ContactKinematic;
use ncollide::query::closest_points_internal;

use object::{BodyHandle, BodyPart, BodySet};
use solver::helper;
use solver::{ForceDirection, NonlinearNormalConeConstraint, NonlinearUnilateralConstraint};
use math::{Isometry, Point, Rotation, Vector};

struct ContactGeometry<N: Real> {
    world1: Point<N>,
    world2: Point<N>,
    normal1: Unit<Vector<N>>,
    normal2: Unit<Vector<N>>,
    normal: Unit<Vector<N>>,
    depth: N,
}

impl<N: Real> ContactGeometry<N> {
    pub fn new(
        world1: Point<N>,
        world2: Point<N>,
        normal1: Unit<Vector<N>>,
        normal2: Unit<Vector<N>>,
        normal: Unit<Vector<N>>,
        depth: N,
    ) -> Self {
        ContactGeometry {
            world1,
            world2,
            normal1,
            normal2,
            normal,
            depth,
        }
    }
}

pub struct NonlinearSORProx<N: Real> {
    _phantom: PhantomData<N>,
}

impl<N: Real> NonlinearSORProx<N> {
    pub fn new() -> Self {
        NonlinearSORProx {
            _phantom: PhantomData,
        }
    }

    pub fn solve(
        &self,
        bodies: &mut BodySet<N>,
        constraints: &mut [NonlinearUnilateralConstraint<N>],
        ncone_constraints: &mut [NonlinearNormalConeConstraint<N>],
        mj_lambda: &mut DVector<N>,
        jacobians: &mut [N],
        max_iter: usize,
    ) {
        for _ in 0..max_iter {
            for constraint in constraints.iter_mut() {
                // FIXME: specialize for SPATIAL_DIM.
                let dim1 = Dynamic::new(constraint.ndofs1);
                let dim2 = Dynamic::new(constraint.ndofs2);
                self.solve_unilateral(bodies, constraint, mj_lambda, jacobians, dim1, dim2);

                // self.solve_normal(
                //     bodies,
                //     constraint,
                //     &mut ncone_constraints[constraint.normal_constraint_id],
                //     mj_lambda,
                //     jacobians,
                //     dim1,
                //     dim2,
                // );
            }
        }
    }

    fn solve_unilateral<D1: Dim, D2: Dim>(
        &self,
        bodies: &mut BodySet<N>,
        constraint: &mut NonlinearUnilateralConstraint<N>,
        mj_lambda: &mut DVector<N>,
        jacobians: &mut [N],
        dim1: D1,
        dim2: D2,
    ) {
        self.update_contact_constraint(bodies, constraint, jacobians);

        let impulse = -constraint.rhs / constraint.inv_r;

        if impulse > N::zero() {
            VectorSliceMutN::new_generic_mut(jacobians, dim1, U1).mul_assign(impulse);
            VectorSliceMutN::new_generic_mut(&mut jacobians[dim1.value()..], dim2, U1)
                .mul_assign(impulse);

            bodies
                .body_mut(constraint.body1)
                .apply_displacement(&jacobians[0..dim1.value()]);
            bodies
                .body_mut(constraint.body2)
                .apply_displacement(&jacobians[dim1.value()..dim1.value() + dim2.value()]);
        }
    }

    fn solve_normal<D1: Dim, D2: Dim>(
        &self,
        bodies: &mut BodySet<N>,
        contact: &NonlinearUnilateralConstraint<N>,
        constraint: &mut NonlinearNormalConeConstraint<N>,
        mj_lambda: &mut DVector<N>,
        jacobians: &mut [N],
        dim1: D1,
        dim2: D2,
    ) {
        if self.update_normal_cone_constraint(bodies, contact, constraint, jacobians) {
            let impulse = -constraint.rhs / constraint.inv_r;

            VectorSliceMutN::new_generic_mut(jacobians, dim1, U1).mul_assign(impulse);
            VectorSliceMutN::new_generic_mut(&mut jacobians[dim1.value()..], dim2, U1)
                .mul_assign(impulse);

            bodies
                .body_mut(contact.body1)
                .apply_displacement(&jacobians[0..dim1.value()]);
            bodies
                .body_mut(contact.body2)
                .apply_displacement(&jacobians[dim1.value()..dim1.value() + dim2.value()]);
        }
    }

    fn compute_contact_geometry(
        &self,
        body1: &BodyPart<N>,
        body2: &BodyPart<N>,
        constraint: &NonlinearUnilateralConstraint<N>,
    ) -> ContactGeometry<N> {
        let m1 = body1.position();
        let m2 = body2.position();

        let mut world1 = m1.transform_point(&constraint.local1);
        let mut world2 = m2.transform_point(&constraint.local2);
        let normal;
        let normal1;
        let normal2;
        let mut depth;

        match constraint.kinematic {
            ContactKinematic::PlanePoint => {
                normal = m1 * constraint.normal1;
                depth = -na::dot(normal.as_ref(), &(world2 - world1));
                world1 = world2 + normal.as_ref() * depth;
                normal1 = constraint.normal1;
                normal2 = -Unit::new_unchecked(m2.inverse_transform_vector(normal.as_ref()));
            }
            ContactKinematic::PointPlane => {
                let world_normal2 = m2 * constraint.normal2.as_ref();
                depth = -na::dot(&world_normal2, &(world1 - world2));
                world2 = world1 + &world_normal2 * depth;
                normal = Unit::new_unchecked(-world_normal2);
                normal1 = Unit::new_unchecked(m1.inverse_transform_vector(normal.as_ref()));
                normal2 = constraint.normal2;
            }
            ContactKinematic::PointPoint => {
                if let Some((n, d)) = Unit::try_new_and_get(world2 - world1, N::default_epsilon()) {
                    depth = -d;
                    normal = n;
                } else {
                    depth = -constraint.margin1 - constraint.margin2;
                    normal = m1 * constraint.normal1;
                }
                normal1 = Unit::new_unchecked(m1.inverse_transform_vector(normal.as_ref()));
                normal2 = -Unit::new_unchecked(m2.inverse_transform_vector(normal.as_ref()));
            }
            ContactKinematic::LinePoint(dir1) => {
                /*
                let mut shift = world2 - world1;
                let proj = na::dot(dir1.as_ref(), &shift);
                shift -= dir1.as_ref() * proj;
                world1 = world2 - shift;

                if let Some((n, d)) = Unit::try_new_and_get(shift, N::zero()) {
                    depth = d;
                    normal = n;
                } else {
                    depth = na::zero();
                    normal = Unit::new_unchecked(m1.transform_vector(constraint.normal1.as_ref()));
                }
                */
                unimplemented!()
            }
            ContactKinematic::PointLine(dir2) => {
                /*
                let mut shift = world1 - world2;
                let proj = na::dot(dir2.as_ref(), &shift);
                shift -= dir2.as_ref() * proj;
                world2 = world1 - shift;

                if let Some((n, d)) = Unit::try_new_and_get(shift, N::zero()) {
                    depth = d;
                    normal = n;
                } else {
                    depth = na::zero();
                    normal = Unit::new_unchecked(m1.transform_vector(constraint.normal1.as_ref()));
                }
                */
                unimplemented!()
            }
            ContactKinematic::LineLine(dir1, dir2) => {
                let world_dir1 = m1 * dir1.unwrap();
                let world_dir2 = m2 * dir2.unwrap();
                let (pt1, pt2) = closest_points_internal::line_against_line(
                    &world1, &world_dir1, &world2, &world_dir2);
                world1 = pt1;
                world2 = pt2;

                if let Some((n, d)) = Unit::try_new_and_get(world2 - world1, N::zero()) {
                    let local_n1 = m1.inverse_transform_vector(n.as_ref());
                    let local_n2 = m2.inverse_transform_vector(&-*n);

                    if constraint.ncone1.contains(&local_n1)
                        && constraint.ncone2.contains(&local_n2)
                    {
                        depth = d;
                        normal = n;
                    } else {
                        depth = -d;
                        normal = -n;
                    }
                } else {
                    depth = na::zero();
                    normal = Unit::new_unchecked(m1.transform_vector(constraint.normal1.as_ref()));
                }

                normal1 = Unit::new_unchecked(m1.inverse_transform_vector(normal.as_ref()));
                normal2 = -Unit::new_unchecked(m2.inverse_transform_vector(normal.as_ref()));
            }
            ContactKinematic::Unknown => {
                depth = N::zero();
                normal = m1 * constraint.normal1;
                normal1 = constraint.normal1;
                normal2 = -Unit::new_unchecked(m2.inverse_transform_vector(normal.as_ref()));
            }
        }

        world1 += normal.unwrap() * constraint.margin1;
        world2 -= normal.unwrap() * constraint.margin2;
        depth += constraint.margin1 + constraint.margin2;

        ContactGeometry::new(world1, world2, normal1, normal2, normal, depth)
    }

    fn update_contact_constraint(
        &self,
        bodies: &BodySet<N>,
        constraint: &mut NonlinearUnilateralConstraint<N>,
        jacobians: &mut [N],
    ) {
        let body1 = bodies.body_part(constraint.body1);
        let body2 = bodies.body_part(constraint.body2);

        let geom = self.compute_contact_geometry(&body1, &body2, constraint);

        let erp: N = na::convert(0.2); // XXX: don't hard-code this.s
        let allowed_error: N = na::convert(0.005); // XXX don't hard-code this.
        let max_correction: N = na::convert(0.2); // XXX don't hard-code this.
        constraint.rhs = na::sup(&(-geom.depth * erp), &(-max_correction)) + allowed_error;

        constraint.inv_r = N::zero();
        helper::fill_constraint_geometry(
            &body1,
            constraint.ndofs1,
            &geom.world1,
            &ForceDirection::Linear(-geom.normal),
            constraint.ndofs1 + constraint.ndofs2,
            0,
            jacobians,
            &mut constraint.inv_r,
        );

        helper::fill_constraint_geometry(
            &body2,
            constraint.ndofs2,
            &geom.world2,
            &ForceDirection::Linear(geom.normal),
            (constraint.ndofs1 * 2) + constraint.ndofs2,
            constraint.ndofs1,
            jacobians,
            &mut constraint.inv_r,
        );

        // May happen sometimes for self-collisions (e.g. a multibody with itself).
        if constraint.inv_r.is_zero() {
            constraint.inv_r = N::one();
        }
    }

    fn update_normal_cone_constraint(
        &self,
        bodies: &BodySet<N>,
        contact: &NonlinearUnilateralConstraint<N>,
        constraint: &mut NonlinearNormalConeConstraint<N>,
        jacobians: &mut [N],
    ) -> bool {
        if contact.rhs >= N::zero() {
            return false;
        }

        let body1 = bodies.body_part(contact.body1);
        let body2 = bodies.body_part(contact.body2);

        let geom = self.compute_contact_geometry(&body1, &body2, contact);

        let closest_n1 = constraint.ncone1.project(&geom.normal1);
        let closest_n2 = constraint.ncone2.project(&geom.normal2);

        // FIXME: could rot1 and rot2 be obtained as a by-product of the projection?
        let rot1;
        let rot2;

        #[cfg(feature = "dim3")]
        {
            // NOTE: we assume the case where both vectors are antipodal
            // (i.e. the result is None) happens too rarely to be handled properly.
            // So if it does, no correction will be made for this iteration.
            let id = Rotation::identity();
            rot1 = Rotation::rotation_between_axis(&geom.normal1, &closest_n1).unwrap_or(id);
            rot2 = Rotation::rotation_between_axis(&geom.normal2, &closest_n2).unwrap_or(id);
        }

        #[cfg(feature = "dim2")]
        {
            rot1 = Rotation::rotation_between_axis(&geom.normal1, &closest_n1);
            rot2 = Rotation::rotation_between_axis(&geom.normal2, &closest_n2);
        }

        let m1 = body1.position();
        let m2 = body2.position();

        let (axis, ang, m) = match (rot1.axis_angle(), rot2.axis_angle()) {
            (None, None) => {
                return false;
            }
            (Some((axis1, ang1)), None) => (axis1, ang1, &m1),
            (None, Some((axis2, ang2))) => (-axis2, ang2, &m2),
            (Some((axis1, ang1)), Some((axis2, ang2))) => {
                if ang1 > ang2 {
                    (axis1, ang1, &m1)
                } else {
                    (-axis2, ang2, &m2)
                }
            }
        };

        let world_axis;
        #[cfg(feature = "dim2")]
        {
            world_axis = axis;
        }

        #[cfg(feature = "dim3")]
        {
            world_axis = m * axis;
        }

        constraint.rhs = -ang; // na::sup(&-ang, &na::convert(-0.02));
                               // println!("Angular stabilization: {}", ang);
        if constraint.rhs >= N::zero() {
            return false;
        }

        // FIXME: for 2D rigid bodies, there is no need to recompute the
        // constraint geometry at each frame because the jacobians will
        // always be the same (except maybe for the sign).
        constraint.inv_r = N::zero();
        helper::fill_constraint_geometry(
            &body1,
            contact.ndofs1,
            &body1.center_of_mass(),
            &ForceDirection::Angular(world_axis),
            contact.ndofs1 + contact.ndofs2,
            0,
            jacobians,
            &mut constraint.inv_r,
        );

        helper::fill_constraint_geometry(
            &body2,
            contact.ndofs2,
            &body2.center_of_mass(),
            &ForceDirection::Angular(-world_axis),
            (contact.ndofs1 * 2) + contact.ndofs2,
            contact.ndofs1,
            jacobians,
            &mut constraint.inv_r,
        );

        // May happen sometimes for self-collisions (e.g. a multibody with itself).
        if constraint.inv_r.is_zero() {
            constraint.inv_r = N::one();
        }

        return true;
    }
}
<|endoftext|>


<commit_before>use std::io::IoResult;

/// Wraps a `Reader` to facilitate reading that is not byte-aligned.
pub struct Bitstream<'r> {
    /// The source where bits are read from.
    reader: &'r mut (Reader + 'r),
    /// Data read from the reader, but not yet fully consumed.
    data: u8,
    /// The number of bits of `data` that have not been consumed.
    bits_left: u8
}

impl<'r> Bitstream<'r> {
    /// Wraps the reader with a reader that facilitates reading individual bits.
    pub fn new(reader: &'r mut Reader) -> Bitstream<'r> {
        Bitstream { reader: reader, data: 0, bits_left: 0 }
    }

    /// Generates a bitmask with 1s in the `bits` most significant bits.
    fn mask_u8(bits: u8) -> u8 {
        debug_assert!(bits <= 8);
        0xffu8 << (8 - bits) as uint
    }

    /// Reads at most eight bits.
    pub fn read_leq_u8(&mut self, bits: u8) -> IoResult<u8> {
        // Of course we can read no more than 8 bits, but we do not want the
        // performance overhead of the assertion, so only do it in debug mode.
        debug_assert!(bits <= 8);

        // If not enough bits left, we will need to read the next byte.
        let result = if self.bits_left < bits {
            // Most significant bits are shifted to the right position already.
            let msb = self.data;

            // From the next byte, we take the additional bits that we need.
            // Those start at the most significant bit, so we need to shift so
            // that it does not overlap with what we have already.
            self.data = try!(self.reader.read_byte());
            let lsb = (self.data & Bitstream::mask_u8(bits - self.bits_left))
                    >> self.bits_left as uint;

            // Shift out the bits that we have consumed.
            self.data = self.data << (bits - self.bits_left) as uint;
            self.bits_left = 8 - (bits - self.bits_left);

            msb | lsb
        } else {
            let result = self.data & Bitstream::mask_u8(bits);

            // Shift out the bits that we have consumed.
            self.data = self.data << bits as uint;
            self.bits_left = self.bits_left - bits;

            result
        };

        // The resulting data is padded with zeroes in the least significant
        // bits, but we want to pad in the most significant bits, so shift.
        Ok(result >> (8 - bits) as uint)
    }
}

#[test]
fn verify_bitstream() {
    use std::io::MemReader;

    let mut data = MemReader::new(vec!(0b1010_0101, 0b1110_0001,
                                       0b1101_0010, 0b0101_0101,
                                       0b0111_0011, 0b0011_1111));
    let mut bits = Bitstream::new(&mut data);

    assert_eq!(bits.read_leq_u8(0).unwrap(), 0);
    assert_eq!(bits.read_leq_u8(1).unwrap(), 1);
    assert_eq!(bits.read_leq_u8(1).unwrap(), 0);
    assert_eq!(bits.read_leq_u8(2).unwrap(), 0b10);
    assert_eq!(bits.read_leq_u8(2).unwrap(), 0b01);
    assert_eq!(bits.read_leq_u8(3).unwrap(), 0b011);
    assert_eq!(bits.read_leq_u8(3).unwrap(), 0b110);
    assert_eq!(bits.read_leq_u8(4).unwrap(), 0b0001);
    assert_eq!(bits.read_leq_u8(5).unwrap(), 0b11010);
    assert_eq!(bits.read_leq_u8(6).unwrap(), 0b010010);
    assert_eq!(bits.read_leq_u8(7).unwrap(), 0b1010101);
    assert_eq!(bits.read_leq_u8(8).unwrap(), 0b11001100);
}
<commit_msg>add ability to align bitstream to the next byte<commit_after>use std::io::IoResult;

/// Wraps a `Reader` to facilitate reading that is not byte-aligned.
pub struct Bitstream<'r> {
    /// The source where bits are read from.
    reader: &'r mut (Reader + 'r),
    /// Data read from the reader, but not yet fully consumed.
    data: u8,
    /// The number of bits of `data` that have not been consumed.
    bits_left: u8
}

impl<'r> Bitstream<'r> {
    /// Wraps the reader with a reader that facilitates reading individual bits.
    pub fn new(reader: &'r mut Reader) -> Bitstream<'r> {
        Bitstream { reader: reader, data: 0, bits_left: 0 }
    }

    /// Generates a bitmask with 1s in the `bits` most significant bits.
    fn mask_u8(bits: u8) -> u8 {
        debug_assert!(bits <= 8);
        0xffu8 << (8 - bits) as uint
    }

    /// Skips bits such that the next read will be byte-aligned.
    pub fn align_to_byte(&mut self) {
        self.bits_left = 0;
    }

    /// Reads at most eight bits.
    pub fn read_leq_u8(&mut self, bits: u8) -> IoResult<u8> {
        // Of course we can read no more than 8 bits, but we do not want the
        // performance overhead of the assertion, so only do it in debug mode.
        debug_assert!(bits <= 8);

        // If not enough bits left, we will need to read the next byte.
        let result = if self.bits_left < bits {
            // Most significant bits are shifted to the right position already.
            let msb = self.data;

            // From the next byte, we take the additional bits that we need.
            // Those start at the most significant bit, so we need to shift so
            // that it does not overlap with what we have already.
            self.data = try!(self.reader.read_byte());
            let lsb = (self.data & Bitstream::mask_u8(bits - self.bits_left))
                    >> self.bits_left as uint;

            // Shift out the bits that we have consumed.
            self.data = self.data << (bits - self.bits_left) as uint;
            self.bits_left = 8 - (bits - self.bits_left);

            msb | lsb
        } else {
            let result = self.data & Bitstream::mask_u8(bits);

            // Shift out the bits that we have consumed.
            self.data = self.data << bits as uint;
            self.bits_left = self.bits_left - bits;

            result
        };

        // The resulting data is padded with zeroes in the least significant
        // bits, but we want to pad in the most significant bits, so shift.
        Ok(result >> (8 - bits) as uint)
    }
}

#[test]
fn verify_bitstream() {
    use std::io::MemReader;

    let mut data = MemReader::new(vec!(0b1010_0101, 0b1110_0001,
                                       0b1101_0010, 0b0101_0101,
                                       0b0111_0011, 0b0011_1111));
    let mut bits = Bitstream::new(&mut data);

    assert_eq!(bits.read_leq_u8(0).unwrap(), 0);
    assert_eq!(bits.read_leq_u8(1).unwrap(), 1);
    assert_eq!(bits.read_leq_u8(1).unwrap(), 0);
    assert_eq!(bits.read_leq_u8(2).unwrap(), 0b10);
    assert_eq!(bits.read_leq_u8(2).unwrap(), 0b01);
    assert_eq!(bits.read_leq_u8(3).unwrap(), 0b011);
    assert_eq!(bits.read_leq_u8(3).unwrap(), 0b110);
    assert_eq!(bits.read_leq_u8(4).unwrap(), 0b0001);
    assert_eq!(bits.read_leq_u8(5).unwrap(), 0b11010);
    assert_eq!(bits.read_leq_u8(6).unwrap(), 0b010010);
    assert_eq!(bits.read_leq_u8(7).unwrap(), 0b1010101);
    assert_eq!(bits.read_leq_u8(8).unwrap(), 0b11001100);
}

#[test]
fn verify_align() {
    use std::io::MemReader;

    let mut data = MemReader::new(vec!(0x00, 0xff));
    let mut bits = Bitstream::new(&mut data);

    assert_eq!(bits.read_leq_u8(5).unwrap(), 0);
    bits.align_to_byte();
    assert_eq!(bits.read_leq_u8(3).unwrap(), 7);
}
<|endoftext|>


<commit_before>//! Defines the BSDF which acts as a container for composing the various BRDFs
//! and BTDFs that describe the surface's properties

use std::vec::Vec;
use collect::enum_set::EnumSet;

use linalg;
use linalg::{Normal, Vector, Point};
use film::Colorf;
use geometry::DifferentialGeometry;
use bxdf::{BxDF, BxDFType};

/// The BSDF contains the various BRDFs and BTDFs that describe the surface's properties
/// at some point. It also transforms incident and outgoing light directions into
/// shading space to make the BxDFs easier to implement.
/// TODO: We really need the memory pool. Each time we get the bsdf from a
/// material we need to allocate a decent amount of stuff since they each need
/// their own tangent, bitangent and differential geometry reference.
pub struct BSDF<'a> {
    /// The hit point
    pub p: Point,
    /// Shading normal, may be perturbed by bump mapping
    pub n: Normal,
    /// The actual geometry normal
    pub ng: Normal,
    /// Tangent vector for the surface
    pub tan: Vector,
    /// Bitangent vector for the surface
    pub bitan: Vector,
    /// Refractive index of the geometry
    pub eta: f32,
    /// TODO: Currently a Vec is safe to use but once in the memory pool it
    /// will leak since it won't be dropped. This would also migrate our BxDFs
    /// from Box<BxDF> to &BxDF. When unboxed traits land we can move to unboxed
    /// BxDFs here though.
    bxdfs: &'a Vec<Box<BxDF + Send + Sync>>,
}

impl<'a> BSDF<'a> {
    /// Create a new BSDF using the BxDFs passed to shade the differential geometry with
    /// refractive index `eta`
    pub fn new(bxdfs: &'a Vec<Box<BxDF + Send + Sync>>, eta: f32,
               dg: &DifferentialGeometry<'a>)
               -> BSDF<'a> {
        let n = dg.n.normalized();
        let tan = linalg::cross(&n, &dg.dp_du.normalized()).normalized();
        let bitan = linalg::cross(&tan, &n).normalized();
        BSDF { p: dg.p, n: n, ng: dg.ng.normalized(), tan: tan, bitan: bitan, bxdfs: bxdfs, eta: eta }
    }
    /// Return the total number of BxDFs
    pub fn num_bxdfs(&self) -> usize { self.bxdfs.len() }
    /// Return the number of BxDFs matching the flags
    pub fn num_matching(&self, flags: EnumSet<BxDFType>) -> usize {
        self.bxdfs.iter().filter(|ref x| x.matches(flags)).count()
    }
    /// Transform the vector from world space to shading space
    pub fn to_shading(&self, v: &Vector) -> Vector {
        Vector::new(linalg::dot(v, &self.bitan), linalg::dot(v, &self.tan),
                    linalg::dot(v, &self.n))
    }
    /// Transform the vectro from shading space to world space
    pub fn from_shading(&self, v: &Vector) -> Vector {
        Vector::new(self.bitan.x * v.x + self.tan.x * v.y + self.n.x * v.z,
                    self.bitan.y * v.x + self.tan.y * v.y + self.n.y * v.z,
                    self.bitan.z * v.x + self.tan.z * v.y + self.n.z * v.z)
    }
    /// Evaluate the BSDF for the outgoing and incident light directions
    /// `w_o` and `w_i` in world space, sampling the desired subset of BxDFs
    /// selected by the flags passed. `wo_world` and `wi_world` should point from
    /// the hit point in the outgoing and incident light directions respectively.
    pub fn eval(&self, wo_world: &Vector, wi_world: &Vector, mut flags: EnumSet<BxDFType>) -> Colorf {
        let w_o = self.to_shading(wo_world);
        let w_i = self.to_shading(wi_world);
        // Determine if we should evaluate reflection or transmission based on the
        // geometry normal and the light directions
        if linalg::dot(wo_world, &self.ng) * linalg::dot(wi_world, &self.ng) > 0.0 {
            flags.remove(&BxDFType::Transmission);
        } else {
            flags.remove(&BxDFType::Reflection);
        }
        // Find all matching BxDFs and add their contribution to the material's color
        self.bxdfs.iter().filter(|ref x| x.matches(flags)).map(|ref x| x.eval(&w_o, &w_i))
            .fold(Colorf::broadcast(0.0), |x, y| x + y)
    }
    /// Sample a component of the BSDF to get an incident light direction for light
    /// leaving the surface along `w_o`. Returns the color, direction and the type
    /// of the BxDF that was sampled. TODO: Need to take random numbers here for proper
    /// sampling. Currently we just find the first that matches which is so incredibly wrong
    /// for proper sampling.
    pub fn sample(&self, wo_world: &Vector, flags: EnumSet<BxDFType>) -> (Colorf, Vector, EnumSet<BxDFType>) {
        let n_matching = self.num_matching(flags);
        if n_matching == 0 {
            return (Colorf::broadcast(0.0), Vector::broadcast(0.0), EnumSet::new());
        }
        // Really bad: just take the first for now. This will be ok for having very basic
        // materials like our single component diffuse and specular but is wrong for
        // more complicated ones
        let bxdf = self.matching_at(0, flags);
        let w_o = self.to_shading(wo_world);
        let (f, w_i) = bxdf.sample(&w_o);
        // TODO: Will fail for later materials - we assume only one matched. For the diffuse
        // and specular metal materials this is correct but not for more complex ones
        (f, self.from_shading(&w_i), bxdf.bxdf_type())
    }
    /// Get the `i`th BxDF that matches the flags passed. There should not be fewer than i
    /// BxDFs that match the flags
    fn matching_at(&self, i: usize, flags: EnumSet<BxDFType>) -> &Box<BxDF + Send + Sync> {
        let mut it = self.bxdfs.iter().filter(|ref x| x.matches(flags)).skip(i);
        match it.next() {
            Some(b) => b,
            None => panic!("Out of bounds index for BxDF type {:?}", flags)
        }
    }
}

<commit_msg>Clean up bsdf init to match PBR more<commit_after>//! Defines the BSDF which acts as a container for composing the various BRDFs
//! and BTDFs that describe the surface's properties

use std::vec::Vec;
use collect::enum_set::EnumSet;

use linalg;
use linalg::{Normal, Vector, Point};
use film::Colorf;
use geometry::DifferentialGeometry;
use bxdf::{BxDF, BxDFType};

/// The BSDF contains the various BRDFs and BTDFs that describe the surface's properties
/// at some point. It also transforms incident and outgoing light directions into
/// shading space to make the BxDFs easier to implement.
/// TODO: We really need the memory pool. Each time we get the bsdf from a
/// material we need to allocate a decent amount of stuff since they each need
/// their own tangent, bitangent and differential geometry reference.
pub struct BSDF<'a> {
    /// The hit point
    pub p: Point,
    /// Shading normal, may be perturbed by bump mapping
    pub n: Normal,
    /// The actual geometry normal
    pub ng: Normal,
    /// Tangent vector for the surface
    pub tan: Vector,
    /// Bitangent vector for the surface
    pub bitan: Vector,
    /// Refractive index of the geometry
    pub eta: f32,
    /// TODO: Currently a Vec is safe to use but once in the memory pool it
    /// will leak since it won't be dropped. This would also migrate our BxDFs
    /// from Box<BxDF> to &BxDF. When unboxed traits land we can move to unboxed
    /// BxDFs here though.
    bxdfs: &'a Vec<Box<BxDF + Send + Sync>>,
}

impl<'a> BSDF<'a> {
    /// Create a new BSDF using the BxDFs passed to shade the differential geometry with
    /// refractive index `eta`
    pub fn new(bxdfs: &'a Vec<Box<BxDF + Send + Sync>>, eta: f32,
               dg: &DifferentialGeometry<'a>)
               -> BSDF<'a> {
        let n = dg.n.normalized();
        let bitan = dg.dp_du.normalized();
        let tan = linalg::cross(&n, &bitan);
        BSDF { p: dg.p, n: n, ng: dg.ng, tan: tan, bitan: bitan, bxdfs: bxdfs, eta: eta }
    }
    /// Return the total number of BxDFs
    pub fn num_bxdfs(&self) -> usize { self.bxdfs.len() }
    /// Return the number of BxDFs matching the flags
    pub fn num_matching(&self, flags: EnumSet<BxDFType>) -> usize {
        self.bxdfs.iter().filter(|ref x| x.matches(flags)).count()
    }
    /// Transform the vector from world space to shading space
    pub fn to_shading(&self, v: &Vector) -> Vector {
        Vector::new(linalg::dot(v, &self.bitan), linalg::dot(v, &self.tan),
                    linalg::dot(v, &self.n))
    }
    /// Transform the vectro from shading space to world space
    pub fn from_shading(&self, v: &Vector) -> Vector {
        Vector::new(self.bitan.x * v.x + self.tan.x * v.y + self.n.x * v.z,
                    self.bitan.y * v.x + self.tan.y * v.y + self.n.y * v.z,
                    self.bitan.z * v.x + self.tan.z * v.y + self.n.z * v.z)
    }
    /// Evaluate the BSDF for the outgoing and incident light directions
    /// `w_o` and `w_i` in world space, sampling the desired subset of BxDFs
    /// selected by the flags passed. `wo_world` and `wi_world` should point from
    /// the hit point in the outgoing and incident light directions respectively.
    pub fn eval(&self, wo_world: &Vector, wi_world: &Vector, mut flags: EnumSet<BxDFType>) -> Colorf {
        let w_o = self.to_shading(wo_world);
        let w_i = self.to_shading(wi_world);
        // Determine if we should evaluate reflection or transmission based on the
        // geometry normal and the light directions
        if linalg::dot(wo_world, &self.ng) * linalg::dot(wi_world, &self.ng) > 0.0 {
            flags.remove(&BxDFType::Transmission);
        } else {
            flags.remove(&BxDFType::Reflection);
        }
        // Find all matching BxDFs and add their contribution to the material's color
        self.bxdfs.iter().filter(|ref x| x.matches(flags)).map(|ref x| x.eval(&w_o, &w_i))
            .fold(Colorf::broadcast(0.0), |x, y| x + y)
    }
    /// Sample a component of the BSDF to get an incident light direction for light
    /// leaving the surface along `w_o`. Returns the color, direction and the type
    /// of the BxDF that was sampled. TODO: Need to take random numbers here for proper
    /// sampling. Currently we just find the first that matches which is so incredibly wrong
    /// for proper sampling.
    pub fn sample(&self, wo_world: &Vector, flags: EnumSet<BxDFType>) -> (Colorf, Vector, EnumSet<BxDFType>) {
        let n_matching = self.num_matching(flags);
        if n_matching == 0 {
            return (Colorf::broadcast(0.0), Vector::broadcast(0.0), EnumSet::new());
        }
        // Really bad: just take the first for now. This will be ok for having very basic
        // materials like our single component diffuse and specular but is wrong for
        // more complicated ones
        let bxdf = self.matching_at(0, flags);
        let w_o = self.to_shading(wo_world);
        let (f, w_i) = bxdf.sample(&w_o);
        // TODO: Will fail for later materials - we assume only one matched. For the diffuse
        // and specular metal materials this is correct but not for more complex ones
        (f, self.from_shading(&w_i), bxdf.bxdf_type())
    }
    /// Get the `i`th BxDF that matches the flags passed. There should not be fewer than i
    /// BxDFs that match the flags
    fn matching_at(&self, i: usize, flags: EnumSet<BxDFType>) -> &Box<BxDF + Send + Sync> {
        let mut it = self.bxdfs.iter().filter(|ref x| x.matches(flags)).skip(i);
        match it.next() {
            Some(b) => b,
            None => panic!("Out of bounds index for BxDF type {:?}", flags)
        }
    }
}

<|endoftext|>


<commit_before>use std::ops::Div;

use rust_decimal::Decimal;

use unit_graph::UnitID;

/// A `CanonicalUnit` is a unit expression in canonical form
///
/// e.g. 'a^x 'b^y 'c^z
///      where 'a, 'b, 'c are units and x, y, z are integers
///
/// The elements are guaranteed to be sorted by UnitID (ascending) and not have any duplicate
/// UnitIDs. No exponent can be zero.
#[derive(Debug, Clone, Default, Hash, PartialEq, Eq)]
pub struct CanonicalUnit(Vec<(UnitID, i64)>);

/// Ensure that the terms are sorted and without duplicates
fn ensure_unit_invariants(terms: &[(UnitID, i64)]) {
    let mut last = None;
    for (term, x) in terms {
        if *x == 0 {
            panic!("bug: exponent in canonical unit was zero: {:?}",
                CanonicalUnit(terms.to_vec()));
        }
        if let Some(last) = last {
            if term == last {
                panic!("bug: duplicate unit in canonical representation: {:?}",
                    CanonicalUnit(terms.to_vec()));
            }
            else if term < last {
                panic!("bug: unsorted unit in canonical representation: {:?}",
                    CanonicalUnit(terms.to_vec()));
            }
        }
        else {
            last = Some(term);
        }
    }
}

macro_rules! unit_invariants_debug {
    ($name:ident) => {
        if cfg!(debug) {
            ensure_unit_invariants(&$name);
        }
    };
}

//FIXME: Implement Mul and invert and then make Div = left * invert(right)
impl<'a> Div<&'a CanonicalUnit> for &'a CanonicalUnit {
    type Output = CanonicalUnit;

    fn div<'b>(self, other: &'b CanonicalUnit) -> Self::Output {
        let mut terms = Vec::new();

        let lhs = &self.0;
        let rhs = &other.0;
        unit_invariants_debug!(lhs);
        unit_invariants_debug!(rhs);
        let mut lhs_i = 0;
        let mut rhs_i = 0;
        while lhs_i < lhs.len() && rhs_i < rhs.len() {
            let (left, x) = lhs[lhs_i];
            let (right, y) = rhs[rhs_i];
            // Left must go after right
            if left > right {
                // Invert exponent since right hand side is on the bottom
                terms.push((right, -y));
                rhs_i += 1;
            }
            // Right must go after left
            else if right > left {
                terms.push((left, x));
                lhs_i += 1;
            }
            // Both are equal and their counts must be subtracted because 'a^x/'a^y = 'a^(x-y)
            else {
                debug_assert!(left == right);
                let exponent = x - y;
                if exponent != 0 {
                    terms.push((left, exponent));
                }
                lhs_i += 1;
                rhs_i += 1;
            }
        }
        // Only one of these loops will run
        while lhs_i < lhs.len() {
            let (left, x) = lhs[lhs_i];
            terms.push((left, x));
            lhs_i += 1;
        }
        while rhs_i < rhs.len() {
            let (right, y) = rhs[rhs_i];
            // Invert exponent since right hand side is on the bottom
            terms.push((right, -y));
            rhs_i += 1;
        }

        ensure_unit_invariants(&terms);
        CanonicalUnit(terms)
    }
}

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

    #[test]
    fn division() {
        let unit1 = CanonicalUnit(vec![(0, 1), (1, 1)]);
        let unit2 = CanonicalUnit(vec![(0, 1), (1, 2), (2, 3)]);
        let expected = CanonicalUnit(vec![(1, -1), (2, -3)]);
        assert_eq!(unit1.div(&unit2), expected);
    }
}
<commit_msg>Really nice testing macros for testing CanonicalUnit<commit_after>use std::ops::Div;

use unit_graph::UnitID;

/// A CanonicalUnit is a unit expression in canonical form
///
/// e.g. 'a^x 'b^y 'c^z
///      where 'a, 'b, 'c are units and x, y, z are integers
///
/// The elements are guaranteed to be sorted by UnitID (ascending) and not have any duplicate
/// UnitIDs. No exponent will be zero.
///
/// The number of terms in a CanonicalUnit can be zero. In that case, the CanonicalUnit represents
/// a "unitless" quantity (denoted '_)
#[derive(Debug, Clone, Default, Hash, PartialEq, Eq)]
pub struct CanonicalUnit(Vec<(UnitID, i64)>);

/// Ensure that the terms are sorted and without duplicates
fn ensure_unit_invariants(terms: &[(UnitID, i64)]) {
    let mut last = None;
    for (term, x) in terms {
        if *x == 0 {
            panic!("bug: exponent in canonical unit was zero: {:?}",
                CanonicalUnit(terms.to_vec()));
        }
        if let Some(last) = last {
            if term == last {
                panic!("bug: duplicate unit in canonical representation: {:?}",
                    CanonicalUnit(terms.to_vec()));
            }
            else if term < last {
                panic!("bug: unsorted unit in canonical representation: {:?}",
                    CanonicalUnit(terms.to_vec()));
            }
        }
        else {
            last = Some(term);
        }
    }
}

macro_rules! unit_invariants_debug {
    ($name:ident) => {
        if cfg!(debug) {
            ensure_unit_invariants(&$name);
        }
    };
}

//FIXME: Implement Mul and invert and then make Div = left * invert(right)
impl<'a> Div<&'a CanonicalUnit> for &'a CanonicalUnit {
    type Output = CanonicalUnit;

    fn div<'b>(self, other: &'b CanonicalUnit) -> Self::Output {
        let mut terms = Vec::new();

        let CanonicalUnit(lhs) = self;
        let CanonicalUnit(rhs) = other;
        unit_invariants_debug!(lhs);
        unit_invariants_debug!(rhs);
        let mut lhs_i = 0;
        let mut rhs_i = 0;
        while lhs_i < lhs.len() && rhs_i < rhs.len() {
            let (left, x) = lhs[lhs_i];
            let (right, y) = rhs[rhs_i];
            // Left must go after right
            if left > right {
                // Invert exponent since right hand side is on the bottom
                terms.push((right, -y));
                rhs_i += 1;
            }
            // Right must go after left
            else if right > left {
                terms.push((left, x));
                lhs_i += 1;
            }
            // Both are equal and their counts must be subtracted because 'a^x/'a^y = 'a^(x-y)
            else {
                debug_assert!(left == right);
                let exponent = x - y;
                if exponent != 0 {
                    terms.push((left, exponent));
                }
                lhs_i += 1;
                rhs_i += 1;
            }
        }
        // Only one of these loops will run
        while lhs_i < lhs.len() {
            let (left, x) = lhs[lhs_i];
            terms.push((left, x));
            lhs_i += 1;
        }
        while rhs_i < rhs.len() {
            let (right, y) = rhs[rhs_i];
            // Invert exponent since right hand side is on the bottom
            terms.push((right, -y));
            rhs_i += 1;
        }

        ensure_unit_invariants(&terms);
        CanonicalUnit(terms)
    }
}

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

    /// Generate variables for some UnitIDs
    ///
    /// unit_ids!(a, b, c) generates:
    ///
    ///    let a: UnitID = 0;
    ///    let b: UnitID = 1;
    ///    let c: UnitID = 2;
    macro_rules! unit_ids {
        // Use default counter
        ($name:ident, $($rest:tt)*) => {
            unit_ids!(0, $name, $($rest)*);
        };
        // Need to make the comma optional
        ($name:ident) => {
            unit_ids!(0, $name);
        };
        // Increment a given counter
        ($count:expr, $name:ident, $($rest:tt)*) => {
            unit_ids!($count, $name);
            unit_ids!($count + 1, $($rest)*);
        };
        // Need to make the comma optional
        ($count:expr, $name:ident) => {
            let $name: UnitID = $count;
        };
        // Base case
        ($count:expr) => ();
    }

    macro_rules! unit {
        ($($unit_name:ident ^ $exp:expr)*) => {
            CanonicalUnit(vec![$(($unit_name, $exp)),*])
        };
    }

    #[test]
    fn division() {
        unit_ids!(a, b, c);
        let unit1 = unit!(a^1 b^1);
        let unit2 = unit!(a^1 b^2 c^3);
        let expected = unit!(b^-1 c^-3);
        assert_eq!(unit1.div(&unit2), expected);
    }
}
<|endoftext|>


<commit_before>#![deny(unused)]
#![cfg_attr(test, deny(warnings))]

#[cfg(test)] extern crate hamcrest;
#[macro_use] extern crate log;
extern crate crates_io as registry;
extern crate crossbeam;
extern crate curl;
extern crate docopt;
extern crate filetime;
extern crate flate2;
extern crate fs2;
extern crate git2;
extern crate glob;
extern crate handlebars;
extern crate libc;
extern crate libgit2_sys;
extern crate num_cpus;
extern crate rustc_serialize;
extern crate semver;
extern crate shell_escape;
extern crate tar;
extern crate tempdir;
extern crate term;
extern crate toml;
extern crate url;

use std::io;
use std::fmt;
use rustc_serialize::{Decodable, Encodable};
use rustc_serialize::json;
use docopt::Docopt;

use core::{Shell, MultiShell, ShellConfig, Verbosity, ColorConfig};
use core::shell::Verbosity::{Verbose};
use term::color::{BLACK};

pub use util::{CargoError, CargoResult, CliError, CliResult, human, Config, ChainError};

macro_rules! bail {
    ($($fmt:tt)*) => (
        return Err(::util::human(&format_args!($($fmt)*)))
    )
}

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub struct CommitInfo {
    pub short_commit_hash: String,
    pub commit_hash: String,
    pub commit_date: String,
}

pub struct CfgInfo {
    // Information about the git repository we may have been built from.
    pub commit_info: Option<CommitInfo>,
    // The date that the build was performed.
    pub build_date: String,
    // The release channel we were built for.
    pub release_channel: String,
}

pub struct VersionInfo {
    pub major: String,
    pub minor: String,
    pub patch: String,
    pub pre_release: Option<String>,
    // Information that's only available when we were built with
    // configure/make, rather than cargo itself.
    pub cfg_info: Option<CfgInfo>,
}

impl fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "cargo-{}.{}.{}",
               self.major, self.minor, self.patch)?;
        match self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
            Some(channel) => {
                if channel != "stable" {
                    write!(f, "-{}", channel)?;
                    let empty = String::from("");
                    write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
                }
            },
            None => (),
        };

        if let Some(ref cfg) = self.cfg_info {
            match cfg.commit_info {
                Some(ref ci) => {
                    write!(f, " ({} {})",
                           ci.short_commit_hash, ci.commit_date)?;
                },
                None => {
                    write!(f, " (built {})",
                           cfg.build_date)?;
                }
            }
        };
        Ok(())
    }
}

pub fn call_main_without_stdin<Flags: Decodable>(
            exec: fn(Flags, &Config) -> CliResult,
            config: &Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult
{
    let docopt = Docopt::new(usage).unwrap()
        .options_first(options_first)
        .argv(args.iter().map(|s| &s[..]))
        .help(true);

    let flags = docopt.decode().map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::new(human(e.to_string()), code)
    })?;

    exec(flags, config)
}

pub fn print_json<T: Encodable>(obj: &T) {
    let encoded = json::encode(&obj).unwrap();
    println!("{}", encoded);
}

pub fn shell(verbosity: Verbosity, color_config: ColorConfig) -> MultiShell {
    enum Output {
        Stdout,
        Stderr,
    }

    let tty = isatty(Output::Stderr);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let err = Shell::create(|| Box::new(io::stderr()), config);

    let tty = isatty(Output::Stdout);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let out = Shell::create(|| Box::new(io::stdout()), config);

    return MultiShell::new(out, err, verbosity);

    #[cfg(unix)]
    fn isatty(output: Output) -> bool {
        let fd = match output {
            Output::Stdout => libc::STDOUT_FILENO,
            Output::Stderr => libc::STDERR_FILENO,
        };

        unsafe { libc::isatty(fd) != 0 }
    }
    #[cfg(windows)]
    fn isatty(output: Output) -> bool {
        extern crate kernel32;
        extern crate winapi;

        let handle = match output {
            Output::Stdout => winapi::winbase::STD_OUTPUT_HANDLE,
            Output::Stderr => winapi::winbase::STD_ERROR_HANDLE,
        };

        unsafe {
            let handle = kernel32::GetStdHandle(handle);
            let mut out = 0;
            kernel32::GetConsoleMode(handle, &mut out) != 0
        }
    }
}

pub fn exit_with_error(err: CliError, shell: &mut MultiShell) -> ! {
    debug!("exit_with_error; err={:?}", err);

    let CliError { error, exit_code, unknown } = err;
    // exit_code == 0 is non-fatal error, e.g. docopt version info
    let fatal = exit_code != 0;

    let hide = unknown && shell.get_verbose() != Verbose;

    if let Some(error) = error {
        let _ignored_result = if hide {
            shell.error("An unknown error occurred")
        } else if fatal {
            shell.error(&error)
        } else {
            shell.say(&error, BLACK)
        };

        if !handle_cause(&error, shell) || hide {
            let _ = shell.err().say("\nTo learn more, run the command again \
                                     with --verbose.".to_string(), BLACK);
        }
    }

    std::process::exit(exit_code)
}

pub fn handle_error(err: &CargoError, shell: &mut MultiShell) {
    debug!("handle_error; err={:?}", err);

    let _ignored_result = shell.error(err);
    handle_cause(err, shell);
}

fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool {
    let verbose = shell.get_verbose();
    let mut err;
    loop {
        cargo_err = match cargo_err.cargo_cause() {
            Some(cause) => cause,
            None => { err = cargo_err.cause(); break }
        };
        if verbose != Verbose && !cargo_err.is_human() { return false }
        print(cargo_err.to_string(), shell);
    }
    loop {
        let cause = match err { Some(err) => err, None => return true };
        if verbose != Verbose { return false }
        print(cause.to_string(), shell);
        err = cause.cause();
    }

    fn print(error: String, shell: &mut MultiShell) {
        let _ = shell.err().say("\nCaused by:", BLACK);
        let _ = shell.err().say(format!("  {}", error), BLACK);
    }
}

pub fn version() -> VersionInfo {
    macro_rules! env_str {
        ($name:expr) => { env!($name).to_string() }
    }
    macro_rules! option_env_str {
        ($name:expr) => { option_env!($name).map(|s| s.to_string()) }
    }
    match option_env!("CFG_RELEASE_CHANNEL") {
        // We have environment variables set up from configure/make.
        Some(_) => {
            let commit_info =
                option_env!("CFG_COMMIT_HASH").map(|s| {
                    CommitInfo {
                        commit_hash: s.to_string(),
                        short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
                        commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
                    }
                });
            VersionInfo {
                major: option_env_str!("CFG_VERSION_MAJOR").unwrap(),
                minor: option_env_str!("CFG_VERSION_MINOR").unwrap(),
                patch: option_env_str!("CFG_VERSION_PATCH").unwrap(),
                pre_release: option_env_str!("CFG_PRERELEASE_VERSION"),
                cfg_info: Some(CfgInfo {
                    build_date: option_env_str!("CFG_BUILD_DATE").unwrap(),
                    release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
                    commit_info: commit_info,
                }),
            }
        },
        // We are being compiled by Cargo itself.
        None => {
            VersionInfo {
                major: env_str!("CARGO_PKG_VERSION_MAJOR"),
                minor: env_str!("CARGO_PKG_VERSION_MINOR"),
                patch: env_str!("CARGO_PKG_VERSION_PATCH"),
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: None,
            }
        }
    }
}
<commit_msg>use space, not dash, in `cargo --version` output<commit_after>#![deny(unused)]
#![cfg_attr(test, deny(warnings))]

#[cfg(test)] extern crate hamcrest;
#[macro_use] extern crate log;
extern crate crates_io as registry;
extern crate crossbeam;
extern crate curl;
extern crate docopt;
extern crate filetime;
extern crate flate2;
extern crate fs2;
extern crate git2;
extern crate glob;
extern crate handlebars;
extern crate libc;
extern crate libgit2_sys;
extern crate num_cpus;
extern crate rustc_serialize;
extern crate semver;
extern crate shell_escape;
extern crate tar;
extern crate tempdir;
extern crate term;
extern crate toml;
extern crate url;

use std::io;
use std::fmt;
use rustc_serialize::{Decodable, Encodable};
use rustc_serialize::json;
use docopt::Docopt;

use core::{Shell, MultiShell, ShellConfig, Verbosity, ColorConfig};
use core::shell::Verbosity::{Verbose};
use term::color::{BLACK};

pub use util::{CargoError, CargoResult, CliError, CliResult, human, Config, ChainError};

macro_rules! bail {
    ($($fmt:tt)*) => (
        return Err(::util::human(&format_args!($($fmt)*)))
    )
}

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub struct CommitInfo {
    pub short_commit_hash: String,
    pub commit_hash: String,
    pub commit_date: String,
}

pub struct CfgInfo {
    // Information about the git repository we may have been built from.
    pub commit_info: Option<CommitInfo>,
    // The date that the build was performed.
    pub build_date: String,
    // The release channel we were built for.
    pub release_channel: String,
}

pub struct VersionInfo {
    pub major: String,
    pub minor: String,
    pub patch: String,
    pub pre_release: Option<String>,
    // Information that's only available when we were built with
    // configure/make, rather than cargo itself.
    pub cfg_info: Option<CfgInfo>,
}

impl fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "cargo {}.{}.{}",
               self.major, self.minor, self.patch)?;
        match self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
            Some(channel) => {
                if channel != "stable" {
                    write!(f, "-{}", channel)?;
                    let empty = String::from("");
                    write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
                }
            },
            None => (),
        };

        if let Some(ref cfg) = self.cfg_info {
            match cfg.commit_info {
                Some(ref ci) => {
                    write!(f, " ({} {})",
                           ci.short_commit_hash, ci.commit_date)?;
                },
                None => {
                    write!(f, " (built {})",
                           cfg.build_date)?;
                }
            }
        };
        Ok(())
    }
}

pub fn call_main_without_stdin<Flags: Decodable>(
            exec: fn(Flags, &Config) -> CliResult,
            config: &Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult
{
    let docopt = Docopt::new(usage).unwrap()
        .options_first(options_first)
        .argv(args.iter().map(|s| &s[..]))
        .help(true);

    let flags = docopt.decode().map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::new(human(e.to_string()), code)
    })?;

    exec(flags, config)
}

pub fn print_json<T: Encodable>(obj: &T) {
    let encoded = json::encode(&obj).unwrap();
    println!("{}", encoded);
}

pub fn shell(verbosity: Verbosity, color_config: ColorConfig) -> MultiShell {
    enum Output {
        Stdout,
        Stderr,
    }

    let tty = isatty(Output::Stderr);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let err = Shell::create(|| Box::new(io::stderr()), config);

    let tty = isatty(Output::Stdout);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let out = Shell::create(|| Box::new(io::stdout()), config);

    return MultiShell::new(out, err, verbosity);

    #[cfg(unix)]
    fn isatty(output: Output) -> bool {
        let fd = match output {
            Output::Stdout => libc::STDOUT_FILENO,
            Output::Stderr => libc::STDERR_FILENO,
        };

        unsafe { libc::isatty(fd) != 0 }
    }
    #[cfg(windows)]
    fn isatty(output: Output) -> bool {
        extern crate kernel32;
        extern crate winapi;

        let handle = match output {
            Output::Stdout => winapi::winbase::STD_OUTPUT_HANDLE,
            Output::Stderr => winapi::winbase::STD_ERROR_HANDLE,
        };

        unsafe {
            let handle = kernel32::GetStdHandle(handle);
            let mut out = 0;
            kernel32::GetConsoleMode(handle, &mut out) != 0
        }
    }
}

pub fn exit_with_error(err: CliError, shell: &mut MultiShell) -> ! {
    debug!("exit_with_error; err={:?}", err);

    let CliError { error, exit_code, unknown } = err;
    // exit_code == 0 is non-fatal error, e.g. docopt version info
    let fatal = exit_code != 0;

    let hide = unknown && shell.get_verbose() != Verbose;

    if let Some(error) = error {
        let _ignored_result = if hide {
            shell.error("An unknown error occurred")
        } else if fatal {
            shell.error(&error)
        } else {
            shell.say(&error, BLACK)
        };

        if !handle_cause(&error, shell) || hide {
            let _ = shell.err().say("\nTo learn more, run the command again \
                                     with --verbose.".to_string(), BLACK);
        }
    }

    std::process::exit(exit_code)
}

pub fn handle_error(err: &CargoError, shell: &mut MultiShell) {
    debug!("handle_error; err={:?}", err);

    let _ignored_result = shell.error(err);
    handle_cause(err, shell);
}

fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool {
    let verbose = shell.get_verbose();
    let mut err;
    loop {
        cargo_err = match cargo_err.cargo_cause() {
            Some(cause) => cause,
            None => { err = cargo_err.cause(); break }
        };
        if verbose != Verbose && !cargo_err.is_human() { return false }
        print(cargo_err.to_string(), shell);
    }
    loop {
        let cause = match err { Some(err) => err, None => return true };
        if verbose != Verbose { return false }
        print(cause.to_string(), shell);
        err = cause.cause();
    }

    fn print(error: String, shell: &mut MultiShell) {
        let _ = shell.err().say("\nCaused by:", BLACK);
        let _ = shell.err().say(format!("  {}", error), BLACK);
    }
}

pub fn version() -> VersionInfo {
    macro_rules! env_str {
        ($name:expr) => { env!($name).to_string() }
    }
    macro_rules! option_env_str {
        ($name:expr) => { option_env!($name).map(|s| s.to_string()) }
    }
    match option_env!("CFG_RELEASE_CHANNEL") {
        // We have environment variables set up from configure/make.
        Some(_) => {
            let commit_info =
                option_env!("CFG_COMMIT_HASH").map(|s| {
                    CommitInfo {
                        commit_hash: s.to_string(),
                        short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
                        commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
                    }
                });
            VersionInfo {
                major: option_env_str!("CFG_VERSION_MAJOR").unwrap(),
                minor: option_env_str!("CFG_VERSION_MINOR").unwrap(),
                patch: option_env_str!("CFG_VERSION_PATCH").unwrap(),
                pre_release: option_env_str!("CFG_PRERELEASE_VERSION"),
                cfg_info: Some(CfgInfo {
                    build_date: option_env_str!("CFG_BUILD_DATE").unwrap(),
                    release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
                    commit_info: commit_info,
                }),
            }
        },
        // We are being compiled by Cargo itself.
        None => {
            VersionInfo {
                major: env_str!("CARGO_PKG_VERSION_MAJOR"),
                minor: env_str!("CARGO_PKG_VERSION_MINOR"),
                patch: env_str!("CARGO_PKG_VERSION_PATCH"),
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: None,
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::error::Error;
use std::fs::{self, File};
use std::path::PathBuf;
use std::io::{BufWriter, Read, Write};

use bincode::{self, Infinite};
use memmap::Mmap;
use serde::Serialize;
use serde::de::DeserializeOwned;

lazy_static! {
    static ref TERRA_DIRECTORY: PathBuf = {
        env::home_dir().unwrap_or(PathBuf::from(".")).join(".terra")
    };
}

pub trait WebAsset {
    type Type;

    fn url(&self) -> String;
    fn filename(&self) -> String;
    fn parse(&self, data: Vec<u8>) -> Result<Self::Type, Box<Error>>;

    fn load(&self) -> Result<Self::Type, Box<Error>> {
        let filename = TERRA_DIRECTORY.join(self.filename());
        let mut data = Vec::<u8>::new();
        if let Ok(mut file) = File::open(&filename) {
            file.read_to_end(&mut data)?;
        } else {
            {
                use curl::easy::Easy;
                let mut easy = Easy::new();
                easy.url(&self.url())?;
                let mut easy = easy.transfer();
                easy.write_function(|d| {
                    let len = d.len();
                    data.extend(d);
                    Ok(len)
                })?;
                easy.perform()?;
            }

            if let Some(parent) = filename.parent() {
                fs::create_dir_all(parent)?;
            }
            let mut file = File::create(filename)?;
            file.write_all(&data)?;
            file.sync_all()?;
        }
        Ok(self.parse(data)?)
    }
}

pub trait GeneratedAsset {
    type Type: Serialize + DeserializeOwned;

    fn filename(&self) -> String;
    fn generate(&self) -> Result<Self::Type, Box<Error>>;

    fn load(&self) -> Result<Self::Type, Box<Error>> {
        let filename = TERRA_DIRECTORY.join(self.filename());
        if let Ok(mut file) = File::open(&filename) {
            let mut contents = Vec::new();
            file.read_to_end(&mut contents)?;
            Ok(bincode::deserialize(&contents)?)
        } else {
            let generated = self.generate()?;
            if let Some(parent) = filename.parent() {
                fs::create_dir_all(parent)?;
            }
            let mut file = File::create(&filename)?;
            {
                let mut writer = BufWriter::new(&mut file);
                bincode::serialize_into(&mut writer, &generated, Infinite)?;
            }
            file.sync_all()?;
            Ok(generated)
        }
    }
}

pub(crate) trait MMappedAsset {
    type Header: Serialize + DeserializeOwned;

    fn filename(&self) -> String;
    fn generate<W: Write>(&self, w: W) -> Result<Self::Header, Box<Error>>;

    fn load(&self) -> Result<(Self::Header, Mmap), Box<Error>> {
        let header_filename = TERRA_DIRECTORY.join(self.filename() + ".hdr");
        let data_filename = TERRA_DIRECTORY.join(self.filename() + ".data");

        if let (Ok(mut header), Ok(data)) =
            (File::open(&header_filename), File::open(&data_filename))
        {
            let mut contents = Vec::new();
            header.read_to_end(&mut contents)?;
            let header = bincode::deserialize(&contents)?;
            let mapping = Mmap::open(&data, ::memmap::Protection::Read)?;
            Ok((header, mapping))
        } else {
            if let Some(parent) = data_filename.parent() {
                fs::create_dir_all(parent)?;
            }
            let mut data_file = File::create(&data_filename)?;
            let header = self.generate(BufWriter::new(&mut data_file))?;
            data_file.sync_all()?;

            let mut header_file = File::create(&header_filename)?;
            {
                let mut writer = BufWriter::new(&mut header_file);
                bincode::serialize_into(&mut writer, &header, Infinite)?;
            }
            header_file.sync_all()?;

            // Open for reading this time
            let data_file = File::open(&data_filename)?;
            let mapping = Mmap::open(&data_file, ::memmap::Protection::Read)?;
            Ok((header, mapping))
        }
    }
}
<commit_msg>Re-download corrupted assets<commit_after>use std::env;
use std::error::Error;
use std::fs::{self, File};
use std::path::PathBuf;
use std::io::{BufWriter, Read, Write};

use bincode::{self, Infinite};
use memmap::Mmap;
use serde::Serialize;
use serde::de::DeserializeOwned;

lazy_static! {
    static ref TERRA_DIRECTORY: PathBuf = {
        env::home_dir().unwrap_or(PathBuf::from(".")).join(".terra")
    };
}

pub trait WebAsset {
    type Type;

    fn url(&self) -> String;
    fn filename(&self) -> String;
    fn parse(&self, data: Vec<u8>) -> Result<Self::Type, Box<Error>>;

    fn load(&self) -> Result<Self::Type, Box<Error>> {
        let filename = TERRA_DIRECTORY.join(self.filename());

        let try_cached = || {
            let mut file = File::open(&filename)?;
            let mut data = Vec::<u8>::new();
            file.read_to_end(&mut data)?;
            self.parse(data)
        };
        if let Ok(asset) = try_cached() {
            return Ok(asset);
        }

        let mut data = Vec::<u8>::new();
        {
            use curl::easy::Easy;
            let mut easy = Easy::new();
            easy.url(&self.url())?;
            let mut easy = easy.transfer();
            easy.write_function(|d| {
                let len = d.len();
                data.extend(d);
                Ok(len)
            })?;
            easy.perform()?;
        }

        if let Some(parent) = filename.parent() {
            fs::create_dir_all(parent)?;
        }
        let mut file = File::create(&filename)?;
        file.write_all(&data)?;
        file.sync_all()?;
        Ok(self.parse(data)?)
    }
}

pub trait GeneratedAsset {
    type Type: Serialize + DeserializeOwned;

    fn filename(&self) -> String;
    fn generate(&self) -> Result<Self::Type, Box<Error>>;

    fn load(&self) -> Result<Self::Type, Box<Error>> {
        let filename = TERRA_DIRECTORY.join(self.filename());
        if let Ok(mut file) = File::open(&filename) {
            let mut contents = Vec::new();
            file.read_to_end(&mut contents)?;
            Ok(bincode::deserialize(&contents)?)
        } else {
            let generated = self.generate()?;
            if let Some(parent) = filename.parent() {
                fs::create_dir_all(parent)?;
            }
            let mut file = File::create(&filename)?;
            {
                let mut writer = BufWriter::new(&mut file);
                bincode::serialize_into(&mut writer, &generated, Infinite)?;
            }
            file.sync_all()?;
            Ok(generated)
        }
    }
}

pub(crate) trait MMappedAsset {
    type Header: Serialize + DeserializeOwned;

    fn filename(&self) -> String;
    fn generate<W: Write>(&self, w: W) -> Result<Self::Header, Box<Error>>;

    fn load(&self) -> Result<(Self::Header, Mmap), Box<Error>> {
        let header_filename = TERRA_DIRECTORY.join(self.filename() + ".hdr");
        let data_filename = TERRA_DIRECTORY.join(self.filename() + ".data");

        if let (Ok(mut header), Ok(data)) =
            (File::open(&header_filename), File::open(&data_filename))
        {
            let mut contents = Vec::new();
            header.read_to_end(&mut contents)?;
            let header = bincode::deserialize(&contents)?;
            let mapping = Mmap::open(&data, ::memmap::Protection::Read)?;
            Ok((header, mapping))
        } else {
            if let Some(parent) = data_filename.parent() {
                fs::create_dir_all(parent)?;
            }
            let mut data_file = File::create(&data_filename)?;
            let header = self.generate(BufWriter::new(&mut data_file))?;
            data_file.sync_all()?;

            let mut header_file = File::create(&header_filename)?;
            {
                let mut writer = BufWriter::new(&mut header_file);
                bincode::serialize_into(&mut writer, &header, Infinite)?;
            }
            header_file.sync_all()?;

            // Open for reading this time
            let data_file = File::open(&data_filename)?;
            let mapping = Mmap::open(&data_file, ::memmap::Protection::Read)?;
            Ok((header, mapping))
        }
    }
}
<|endoftext|>


<commit_before>extern crate notify;
extern crate git2;
extern crate yaml_rust;
extern crate glob;

use std::process::Command as ShellCommand;
use std::sync::mpsc::channel;
use self::glob::Pattern;

use self::notify::{RecommendedWatcher, Watcher};
use self::yaml_rust::{Yaml, YamlLoader};

use cli::Command;

/// # WatchCommand
///
/// Starts watcher to listen the change events configured
/// in watch.yaml
///
pub struct WatchCommand {
    watches: Watches,
}

impl WatchCommand {
    pub fn new() -> Self {
    let file_content = "
- name: my source
  when:
    change: '**/src/**'
    run: 'it works!'
";
        WatchCommand {
            watches: Watches::from(file_content)
        }
    }
}

impl Command for WatchCommand {

    fn execute(&self) -> Result<(), &str>{

        let (tx, rx) = channel();
        let mut watcher: RecommendedWatcher = match Watcher::new(tx) {
            Ok(w) => w,
            Err(err) => panic!("Error while trying watch. Cause: {:?}",err)
        };

        match watcher.watch(".") {
            Ok(()) => {},
            Err(_) => panic!("Unable to watch current directory"),
        }

        println!("Watching.");
        while let Ok(event) = rx.recv() {
            let watch = match event.path {
               Some(path_buf) => {
                   let path = path_buf.to_str().unwrap();
                   println!("path {:?}", path);

                   match self.watches.watch(&path) {
                       Some(cmd) => println!("comand: {:?}", cmd),
                       None => println!("No command for this watch.")
                   }
               },
               None => println!("No path event.")
            };
        };
        Ok(())
    }

    fn help(&self) -> &str {
        " Watch command.
It starts to watch folders and execute the commands
that are located in events.yaml.

Example:
   # yaml file
   - name: says hello
     when:
       change: 'myfile.txt'
       do: 'echo \"Hello\"'
"
    }
}

/// # Watches
///
/// Represent all items in the yaml config loaded.
///
struct Watches {
    items: Vec<Yaml>,
}
impl Watches {
    pub fn from(plain_text: &str) -> Self{
        Watches {
            items: YamlLoader::load_from_str(&plain_text).unwrap(),
        }
    }

    /// Returns the first watch found for the given path
    /// it may return None if there is no item that match.
    ///
    pub fn watch(&self, path: &str) -> Option<ShellCommand>{
        for w in &self.items {
            let watched_path = w[0]["when"]["change"].as_str().unwrap();
            let watched_command = w[0]["when"]["run"].as_str().unwrap();
            println!("{:?} {:?}", watched_path, path);

            if Pattern::new(watched_path).unwrap().matches(path){
                return Some(ShellCommand::new(watched_command))
            }
        };
        None
    }
}

#[test]
fn it_loads_from_yaml_file() {
    let file_content = "
- name: my tests
  when:
    change: tests/*
    run: cargo tests
";
    let content = YamlLoader::load_from_str(&file_content).unwrap();
    let watches = Watches::from(file_content);
    assert_eq!(content[0], watches.items[0]);
    assert_eq!(content[0]["when"], watches.items[0]["when"]);
    assert_eq!(content[0]["when"]["change"],
               watches.items[0]["when"]["change"])
}

#[test]
fn it_watches_test_path() {
    let file_content = "
- name: my tests
  when:
    change: '**/tests/**'
    run: 'cargo tests'
";
    let watches = Watches::from(file_content);
    assert!(watches.watch("/Users/crosa/others/funzzy/tests/test.rs").is_some());
    assert!(watches.watch("tests/tests.rs").is_some());
    assert!(watches.watch("tests/ruby.rb").is_some());
    assert!(watches.watch("tests/folder/other.rs").is_some())
}

#[test]
fn it_doesnot_watches_test_path() {
    let file_content = "
- name: my source
  when:
    change: '*/funzzy/src/**'
    run: 'cargo build'
";
    let watches = Watches::from(file_content);

    assert!(watches.watch("/Users/crosa/others/funzzy/events.yaml").is_none());
    assert!(watches.watch("tests/").is_none());
    assert!(watches.watch("tests/test.rs").is_none());
    assert!(watches.watch("tests/folder/other.rs").is_none());
}
<commit_msg>feat: executing configured commands<commit_after>extern crate notify;
extern crate git2;
extern crate yaml_rust;
extern crate glob;

use std::process::Command as ShellCommand;
use std::sync::mpsc::channel;
use self::glob::Pattern;

use self::notify::{RecommendedWatcher, Watcher};
use self::yaml_rust::{Yaml, YamlLoader};

use cli::Command;

/// # WatchCommand
///
/// Starts watcher to listen the change events configured
/// in watch.yaml
///
pub struct WatchCommand {
    watches: Watches,
}

impl WatchCommand {
    pub fn new() -> Self {
    let file_content = "
- name: Demo
  when:
    change: '**/src/**'
    run: ls -a
";
        WatchCommand {
            watches: Watches::from(file_content)
        }
    }
}

impl Command for WatchCommand {

    fn execute(&self) -> Result<(), &str>{

        let (tx, rx) = channel();
        let mut watcher: RecommendedWatcher = match Watcher::new(tx) {
            Ok(w) => w,
            Err(err) => panic!("Error while trying watch. Cause: {:?}",err)
        };

        match watcher.watch(".") {
            Ok(()) => {},
            Err(_) => panic!("Unable to watch current directory"),
        }

        println!("Watching.");
        while let Ok(event) = rx.recv() {
            let watch = match event.path {
               Some(path_buf) => {
                   let path = path_buf.to_str().unwrap();
                   println!("path {:?}", path);

                   match self.watches.watch(&path) {
                       Some(mut cmd) => {
                           println!("comand: {:?}", cmd);
                           match cmd.status() {
                               Ok(_) => println!("executed"),
                               Err(err) => println!("Error {:?}", err),
                           };
                       },
                       None => println!("No command for this watch.")
                   }
               },
               None => println!("No path event.")
            };
        };
        Ok(())
    }

    fn help(&self) -> &str {
        " Watch command.
It starts to watch folders and execute the commands
that are located in events.yaml.

Example:
   # yaml file
   - name: says hello
     when:
       change: 'myfile.txt'
       do: 'echo \"Hello\"'
"
    }
}

/// # Watches
///
/// Represent all items in the yaml config loaded.
///
struct Watches {
    items: Vec<Yaml>,
}
impl Watches {
    pub fn from(plain_text: &str) -> Self{
        Watches {
            items: YamlLoader::load_from_str(&plain_text).unwrap(),
        }
    }

    /// Returns the first watch found for the given path
    /// it may return None if there is no item that match.
    ///
    pub fn watch(&self, path: &str) -> Option<ShellCommand>{
        for w in &self.items {
            let watched_path = w[0]["when"]["change"].as_str().unwrap();
            let watched_command = w[0]["when"]["run"].as_str().unwrap();
            println!("{:?} {:?}", watched_path, path);

            if Pattern::new(watched_path).unwrap().matches(path){
                let mut args: Vec<&str>= watched_command.split(' ').collect();
                let cmd = args.remove(0);
                println!("command {} args: {:?}", cmd, args);
                let mut shell = ShellCommand::new(cmd);
                shell.args(&args);
                return Some(shell)
            }
        };
        None
    }
}

#[test]
fn it_loads_from_yaml_file() {
    let file_content = "
- name: my tests
  when:
    change: tests/*
    run: cargo tests
";
    let content = YamlLoader::load_from_str(&file_content).unwrap();
    let watches = Watches::from(file_content);
    assert_eq!(content[0], watches.items[0]);
    assert_eq!(content[0]["when"], watches.items[0]["when"]);
    assert_eq!(content[0]["when"]["change"],
               watches.items[0]["when"]["change"])
}

#[test]
fn it_watches_test_path() {
    let file_content = "
- name: my tests
  when:
    change: '**/tests/**'
    run: 'cargo tests'
";
    let watches = Watches::from(file_content);
    assert!(watches.watch("/Users/crosa/others/funzzy/tests/test.rs").is_some());
    assert!(watches.watch("tests/tests.rs").is_some());
    assert!(watches.watch("tests/ruby.rb").is_some());
    assert!(watches.watch("tests/folder/other.rs").is_some())
}

#[test]
fn it_doesnot_watches_test_path() {
    let file_content = "
- name: my source
  when:
    change: '**/src/**'
    run: 'cargo build'
";
    let watches = Watches::from(file_content);

    assert!(watches.watch("/Users/crosa/others/funzzy/events.yaml").is_none());
    assert!(watches.watch("tests/").is_none());
    assert!(watches.watch("tests/test.rs").is_none());
    assert!(watches.watch("tests/folder/other.rs").is_none());
}

#[test]
fn it_creates_shell_command() {
    let file_content = "
- name: my source
  when:
    change: '**/src/**'
    run: 'cargo build'
";
    let watches = Watches::from(file_content);
    let result = watches.watch("src/test.rs").unwrap();
    let mut expected = ShellCommand::new("cargo");
    expected.arg("build");
    assert_eq!(format!("{:?}", expected),  format!("{:?}", result))
}
<|endoftext|>