<commit_before>use std::slice;
use std::ops::{Add, Sub};
use std::f32::consts::PI;
use std::cmp::max;
use rand::{Rand, Rng};
use num::Integer;
use euclid::Point2D;

/// Hex grid geometry for vectors.
pub trait HexGeom {
    /// Hex distance represented by a vector.
    fn hex_dist(&self) -> i32;
}

impl HexGeom for Point2D<i32> {
    fn hex_dist(&self) -> i32 {
        if self.x.signum() == self.y.signum() {
            max(self.x.abs(), self.y.abs())
        } else {
            self.x.abs() + self.y.abs()
        }
    }
}

/// Hex grid directions.
#[derive(Copy, Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum Dir6 {
    North = 0,
    NorthEast,
    SouthEast,
    South,
    SouthWest,
    NorthWest,
}

impl Dir6 {
    /// Convert a vector into the closest hex direction.
    ///
    /// ```notrust
    ///        *0*       *1*
    ///           \ 14 15 | 00 01
    ///           13\     |      02
    ///               \   |
    ///         12      \ |        03
    ///     *5* ----------O-X------- *2*
    ///         11        Y \      04
    ///                   |   \
    ///           10      |     \05
    ///             09 08 | 07 06 \
    ///                  *4*       *3*
    ///
    /// The hexadecants (00 to 15) and the hex
    /// directions (*0* to *5*) around the origin.
    /// ```
    ///
    /// Vectors that are in a space between two hex direction vectors are
    /// rounded to a hexadecant, then assigned the hex direction whose vector
    /// is nearest to that hexadecant.
    pub fn from_v2(v: Point2D<i32>) -> Dir6 {
        let hexadecant = {
            let width = PI / 8.0;
            let mut radian = (v.x as f32).atan2(-v.y as f32);
            if radian < 0.0 {
                radian += 2.0 * PI
            }
            (radian / width).floor() as i32
        };

        Dir6::from_int(match hexadecant {
            13 | 14 => 0,
            15 | 0 | 1 => 1,
            2 | 3 | 4 => 2,
            5 | 6 => 3,
            7 | 8 | 9 => 4,
            10 | 11 | 12 => 5,
            _ => panic!("Bad hexadecant"),
        })
    }

    /// Convert an integer to a hex dir using modular arithmetic.
    pub fn from_int(i: i32) -> Dir6 { DIRS[i.mod_floor(&6) as usize] }

    /// Convert a hex dir into the corresponding unit vector.
    pub fn to_v2(&self) -> Point2D<i32> {
        let v = [[-1, -1], [0, -1], [1, 0], [1, 1], [0, 1], [-1, 0]][*self as usize];
        Point2D::new(v[0], v[1])
    }

    /// Iterate through the six hex dirs in the standard order.
    pub fn iter() -> slice::Iter<'static, Dir6> { DIRS.iter() }
}

impl Add<i32> for Dir6 {
    type Output = Dir6;
    fn add(self, other: i32) -> Dir6 { Dir6::from_int(self as i32 + other) }
}

impl Sub<i32> for Dir6 {
    type Output = Dir6;
    fn sub(self, other: i32) -> Dir6 { Dir6::from_int(self as i32 - other) }
}

impl Rand for Dir6 {
    fn rand<R: Rng>(rng: &mut R) -> Dir6 { Dir6::from_int(rng.gen_range(0, 6)) }
}

static DIRS: [Dir6; 6] = [Dir6::North,
                          Dir6::NorthEast,
                          Dir6::SouthEast,
                          Dir6::South,
                          Dir6::SouthWest,
                          Dir6::NorthWest];

/// Hex grid directions with transitional directions.
#[derive(Copy, Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum Dir12 {
    North = 0,
    NorthNorthEast,
    NorthEast,
    East,
    SouthEast,
    SouthSouthEast,
    South,
    SouthSouthWest,
    SouthWest,
    West,
    NorthWest,
    NorthNorthWest,
}

impl Dir12 {
    /// If there is exactly one cluster of neighbors in the neighbor mask,
    /// return a direction pointing away from that cluster.
    pub fn away_from(neighbors: &[bool; 6]) -> Option<Dir12> {
        use std::mem;

        let (begin, end) = match find_cluster(neighbors) {
            Some((a, b)) => (a, b),
            None => return None,
        };

        if !is_single_cluster(neighbors, begin, end) {
            return None;
        }

        let cluster_size = if end < begin { end + 6 - begin } else { end - begin };
        assert!(cluster_size > 0);

        // Dir12 in use from here on.
        let center_dir = begin * 2 + (cluster_size - 1);
        let away_dir: u8 = ((center_dir + 6) % 12) as u8;
        assert!(away_dir < 12);

        // XXX: Unsafe because I'm too lazy to do int conversion func by hand.
        return Some(unsafe { mem::transmute(away_dir) });

        fn find_cluster(neighbors: &[bool; 6]) -> Option<(usize, usize)> {
            // Start of the active cluster, inclusive.
            let mut cluster_start = None;
            // End of the active cluster, exclusive.
            let mut cluster_end = None;

            for i in 0..6 {
                if cluster_start.is_none() && neighbors[i] && !neighbors[(i + 5) % 6] {
                    cluster_start = Some(i);
                }

                if cluster_end.is_none() && !neighbors[i] && neighbors[(i + 5) % 6] {
                    cluster_end = Some(i);
                }
            }

            if cluster_start.is_none() {
                return None;
            }

            assert!(cluster_end.is_some()); // Must be some if start is some.

            Some((cluster_start.unwrap(), cluster_end.unwrap()))
        }

        fn is_single_cluster(neighbors: &[bool; 6], start: usize, end: usize) -> bool {
            let mut in_cluster = true;

            for i in 0..6 {
                if (start + i) % 6 == end {
                    in_cluster = false;
                }

                if neighbors[(start + i) % 6] != in_cluster {
                    return false;
                }
            }

            true
        }
    }
}

#[cfg(test)]
mod test {
    use euclid::Point2D;
    use super::Dir6;
    use super::Dir6::*;
    use super::Dir12;

    #[test]
    fn test_dir6() {
        assert_eq!(North, Dir6::from_int(0));
        assert_eq!(NorthWest, Dir6::from_int(-1));
        assert_eq!(NorthWest, Dir6::from_int(5));
        assert_eq!(NorthEast, Dir6::from_int(1));

        assert_eq!(NorthEast, Dir6::from_v2(Point2D::new(20i32, -21i32)));
        assert_eq!(SouthEast, Dir6::from_v2(Point2D::new(20, -10)));
        assert_eq!(North, Dir6::from_v2(Point2D::new(-10, -10)));
        assert_eq!(South, Dir6::from_v2(Point2D::new(1, 1)));

        for i in 0..6 {
            let d = Dir6::from_int(i);
            let v = d.to_v2();
            let v1 = Dir6::from_int(i - 1).to_v2();
            let v2 = Dir6::from_int(i + 1).to_v2();

            // Test static iter
            assert_eq!(Some(d), Dir6::iter().nth(i as usize).map(|&x| x));

            // Test vector mapping.
            assert_eq!(d, Dir6::from_v2(v));

            // Test opposite dir vector mapping.
            assert_eq!(Dir6::from_int(i + 3),
                       Dir6::from_v2(Point2D::new(-v.x, -v.y)));

            // Test approximation of longer vectors.
            assert_eq!(d, Dir6::from_v2(Point2D::new(v.x * 3, v.y * 3)));
            assert_eq!(d,
                       Dir6::from_v2(Point2D::new(v.x * 3 + v1.x, v.y * 3 + v1.y)));
            assert_eq!(d,
                       Dir6::from_v2(Point2D::new(v.x * 3 + v2.x, v.y * 3 + v2.y)));
        }
    }

    #[test]
    fn test_dir12() {
        assert_eq!(None,
                   Dir12::away_from(&[false, false, false, false, false, false]));
        assert_eq!(None,
                   Dir12::away_from(&[true, true, true, true, true, true]));
        assert_eq!(None,
                   Dir12::away_from(&[false, true, false, false, true, false]));
        assert_eq!(None,
                   Dir12::away_from(&[true, true, false, true, false, false]));
        assert_eq!(None,
                   Dir12::away_from(&[true, false, true, false, true, false]));
        assert_eq!(Some(Dir12::South),
                   Dir12::away_from(&[true, false, false, false, false, false]));
        assert_eq!(Some(Dir12::East),
                   Dir12::away_from(&[true, false, false, true, true, true]));
        assert_eq!(Some(Dir12::SouthSouthWest),
                   Dir12::away_from(&[true, true, false, false, false, false]));
        assert_eq!(Some(Dir12::SouthWest),
                   Dir12::away_from(&[true, true, true, false, false, false]));
        assert_eq!(Some(Dir12::SouthSouthEast),
                   Dir12::away_from(&[true, true, false, false, true, true]));
    }
}
<commit_msg>Fix compass direction capitalization<commit_after>use std::slice;
use std::ops::{Add, Sub};
use std::f32::consts::PI;
use std::cmp::max;
use rand::{Rand, Rng};
use num::Integer;
use euclid::Point2D;

/// Hex grid geometry for vectors.
pub trait HexGeom {
    /// Hex distance represented by a vector.
    fn hex_dist(&self) -> i32;
}

impl HexGeom for Point2D<i32> {
    fn hex_dist(&self) -> i32 {
        if self.x.signum() == self.y.signum() {
            max(self.x.abs(), self.y.abs())
        } else {
            self.x.abs() + self.y.abs()
        }
    }
}

/// Hex grid directions.
#[derive(Copy, Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum Dir6 {
    North = 0,
    Northeast,
    Southeast,
    South,
    Southwest,
    Northwest,
}

impl Dir6 {
    /// Convert a vector into the closest hex direction.
    ///
    /// ```notrust
    ///        *0*       *1*
    ///           \ 14 15 | 00 01
    ///           13\     |      02
    ///               \   |
    ///         12      \ |        03
    ///     *5* ----------O-X------- *2*
    ///         11        Y \      04
    ///                   |   \
    ///           10      |     \05
    ///             09 08 | 07 06 \
    ///                  *4*       *3*
    ///
    /// The hexadecants (00 to 15) and the hex
    /// directions (*0* to *5*) around the origin.
    /// ```
    ///
    /// Vectors that are in a space between two hex direction vectors are
    /// rounded to a hexadecant, then assigned the hex direction whose vector
    /// is nearest to that hexadecant.
    pub fn from_v2(v: Point2D<i32>) -> Dir6 {
        let hexadecant = {
            let width = PI / 8.0;
            let mut radian = (v.x as f32).atan2(-v.y as f32);
            if radian < 0.0 {
                radian += 2.0 * PI
            }
            (radian / width).floor() as i32
        };

        Dir6::from_int(match hexadecant {
            13 | 14 => 0,
            15 | 0 | 1 => 1,
            2 | 3 | 4 => 2,
            5 | 6 => 3,
            7 | 8 | 9 => 4,
            10 | 11 | 12 => 5,
            _ => panic!("Bad hexadecant"),
        })
    }

    /// Convert an integer to a hex dir using modular arithmetic.
    pub fn from_int(i: i32) -> Dir6 { DIRS[i.mod_floor(&6) as usize] }

    /// Convert a hex dir into the corresponding unit vector.
    pub fn to_v2(&self) -> Point2D<i32> {
        let v = [[-1, -1], [0, -1], [1, 0], [1, 1], [0, 1], [-1, 0]][*self as usize];
        Point2D::new(v[0], v[1])
    }

    /// Iterate through the six hex dirs in the standard order.
    pub fn iter() -> slice::Iter<'static, Dir6> { DIRS.iter() }
}

impl Add<i32> for Dir6 {
    type Output = Dir6;
    fn add(self, other: i32) -> Dir6 { Dir6::from_int(self as i32 + other) }
}

impl Sub<i32> for Dir6 {
    type Output = Dir6;
    fn sub(self, other: i32) -> Dir6 { Dir6::from_int(self as i32 - other) }
}

impl Rand for Dir6 {
    fn rand<R: Rng>(rng: &mut R) -> Dir6 { Dir6::from_int(rng.gen_range(0, 6)) }
}

static DIRS: [Dir6; 6] = [Dir6::North,
                          Dir6::Northeast,
                          Dir6::Southeast,
                          Dir6::South,
                          Dir6::Southwest,
                          Dir6::Northwest];

/// Hex grid directions with transitional directions.
#[derive(Copy, Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum Dir12 {
    North = 0,
    NorthNortheast,
    Northeast,
    East,
    Southeast,
    SouthSoutheast,
    South,
    SouthSouthwest,
    Southwest,
    West,
    Northwest,
    NorthNorthwest,
}

impl Dir12 {
    /// If there is exactly one cluster of neighbors in the neighbor mask,
    /// return a direction pointing away from that cluster.
    pub fn away_from(neighbors: &[bool; 6]) -> Option<Dir12> {
        use std::mem;

        let (begin, end) = match find_cluster(neighbors) {
            Some((a, b)) => (a, b),
            None => return None,
        };

        if !is_single_cluster(neighbors, begin, end) {
            return None;
        }

        let cluster_size = if end < begin { end + 6 - begin } else { end - begin };
        assert!(cluster_size > 0);

        // Dir12 in use from here on.
        let center_dir = begin * 2 + (cluster_size - 1);
        let away_dir: u8 = ((center_dir + 6) % 12) as u8;
        assert!(away_dir < 12);

        // XXX: Unsafe because I'm too lazy to do int conversion func by hand.
        return Some(unsafe { mem::transmute(away_dir) });

        fn find_cluster(neighbors: &[bool; 6]) -> Option<(usize, usize)> {
            // Start of the active cluster, inclusive.
            let mut cluster_start = None;
            // End of the active cluster, exclusive.
            let mut cluster_end = None;

            for i in 0..6 {
                if cluster_start.is_none() && neighbors[i] && !neighbors[(i + 5) % 6] {
                    cluster_start = Some(i);
                }

                if cluster_end.is_none() && !neighbors[i] && neighbors[(i + 5) % 6] {
                    cluster_end = Some(i);
                }
            }

            if cluster_start.is_none() {
                return None;
            }

            assert!(cluster_end.is_some()); // Must be some if start is some.

            Some((cluster_start.unwrap(), cluster_end.unwrap()))
        }

        fn is_single_cluster(neighbors: &[bool; 6], start: usize, end: usize) -> bool {
            let mut in_cluster = true;

            for i in 0..6 {
                if (start + i) % 6 == end {
                    in_cluster = false;
                }

                if neighbors[(start + i) % 6] != in_cluster {
                    return false;
                }
            }

            true
        }
    }
}

#[cfg(test)]
mod test {
    use euclid::Point2D;
    use super::Dir6;
    use super::Dir6::*;
    use super::Dir12;

    #[test]
    fn test_dir6() {
        assert_eq!(North, Dir6::from_int(0));
        assert_eq!(Northwest, Dir6::from_int(-1));
        assert_eq!(Northwest, Dir6::from_int(5));
        assert_eq!(Northeast, Dir6::from_int(1));

        assert_eq!(Northeast, Dir6::from_v2(Point2D::new(20i32, -21i32)));
        assert_eq!(Southeast, Dir6::from_v2(Point2D::new(20, -10)));
        assert_eq!(North, Dir6::from_v2(Point2D::new(-10, -10)));
        assert_eq!(South, Dir6::from_v2(Point2D::new(1, 1)));

        for i in 0..6 {
            let d = Dir6::from_int(i);
            let v = d.to_v2();
            let v1 = Dir6::from_int(i - 1).to_v2();
            let v2 = Dir6::from_int(i + 1).to_v2();

            // Test static iter
            assert_eq!(Some(d), Dir6::iter().nth(i as usize).map(|&x| x));

            // Test vector mapping.
            assert_eq!(d, Dir6::from_v2(v));

            // Test opposite dir vector mapping.
            assert_eq!(Dir6::from_int(i + 3),
                       Dir6::from_v2(Point2D::new(-v.x, -v.y)));

            // Test approximation of longer vectors.
            assert_eq!(d, Dir6::from_v2(Point2D::new(v.x * 3, v.y * 3)));
            assert_eq!(d,
                       Dir6::from_v2(Point2D::new(v.x * 3 + v1.x, v.y * 3 + v1.y)));
            assert_eq!(d,
                       Dir6::from_v2(Point2D::new(v.x * 3 + v2.x, v.y * 3 + v2.y)));
        }
    }

    #[test]
    fn test_dir12() {
        assert_eq!(None,
                   Dir12::away_from(&[false, false, false, false, false, false]));
        assert_eq!(None,
                   Dir12::away_from(&[true, true, true, true, true, true]));
        assert_eq!(None,
                   Dir12::away_from(&[false, true, false, false, true, false]));
        assert_eq!(None,
                   Dir12::away_from(&[true, true, false, true, false, false]));
        assert_eq!(None,
                   Dir12::away_from(&[true, false, true, false, true, false]));
        assert_eq!(Some(Dir12::South),
                   Dir12::away_from(&[true, false, false, false, false, false]));
        assert_eq!(Some(Dir12::East),
                   Dir12::away_from(&[true, false, false, true, true, true]));
        assert_eq!(Some(Dir12::SouthSouthwest),
                   Dir12::away_from(&[true, true, false, false, false, false]));
        assert_eq!(Some(Dir12::Southwest),
                   Dir12::away_from(&[true, true, true, false, false, false]));
        assert_eq!(Some(Dir12::SouthSoutheast),
                   Dir12::away_from(&[true, true, false, false, true, true]));
    }
}
<|endoftext|>


<commit_before>use camera::Camera;
use event::{Action, Key, MouseButton, WindowEvent};
use na::{self, Isometry3, Matrix4, Perspective3, Point3, Vector2, Vector3};
use resource::ShaderUniform;
use std::f32;
use window::Canvas;

/// Arc-ball camera mode.
///
/// An arc-ball camera is a camera rotating around a fixed point (the focus point) and always
/// looking at it. The following inputs are handled:
///
/// * Left button press + drag - rotates the camera around the focus point
/// * Right button press + drag - translates the focus point on the plane orthogonal to the view
/// direction
/// * Scroll in/out - zoom in/out
/// * Enter key - set the focus point to the origin
#[derive(Clone, Debug)]
pub struct ArcBall {
    /// The focus point.
    at: Point3<f32>,
    /// Yaw of the camera (rotation along the y axis).
    yaw: f32,
    /// Pitch of the camera (rotation along the x axis).
    pitch: f32,
    /// Distance from the camera to the `at` focus point.
    dist: f32,
    /// Minimum distance from the camera to the `at` focus point.
    min_dist: f32,
    /// Maximum distance from the camera to the `at` focus point.
    max_dist: f32,

    /// Increment of the yaw per unit mouse movement. The default value is 0.005.
    yaw_step: f32,
    /// Increment of the pitch per unit mouse movement. The default value is 0.005.
    pitch_step: f32,
    /// Increment of the distance per unit scrolling. The default value is 40.0.
    dist_step: f32,
    rotate_button: Option<MouseButton>,
    drag_button: Option<MouseButton>,
    reset_key: Option<Key>,

    projection: Perspective3<f32>,
    view: Matrix4<f32>,
    proj: Matrix4<f32>,
    proj_view: Matrix4<f32>,
    inverse_proj_view: Matrix4<f32>,
    last_cursor_pos: Vector2<f32>,
    up_axis: Vector3<f32>,
}

impl ArcBall {
    /// Create a new arc-ball camera.
    pub fn new(eye: Point3<f32>, at: Point3<f32>) -> ArcBall {
        ArcBall::new_with_frustrum(f32::consts::PI / 4.0, 0.1, 1024.0, eye, at)
    }

    /// Creates a new arc ball camera with default sensitivity values.
    pub fn new_with_frustrum(
        fov: f32,
        znear: f32,
        zfar: f32,
        eye: Point3<f32>,
        at: Point3<f32>,
    ) -> ArcBall {
        let mut res = ArcBall {
            at: Point3::new(0.0, 0.0, 0.0),
            yaw: 0.0,
            pitch: 0.0,
            dist: 0.0,
            min_dist: 0.00001,
            max_dist: std::f32::MAX,
            yaw_step: 0.005,
            pitch_step: 0.005,
            dist_step: 40.0,
            rotate_button: Some(MouseButton::Button1),
            drag_button: Some(MouseButton::Button2),
            reset_key: Some(Key::Return),
            projection: Perspective3::new(800.0 / 600.0, fov, znear, zfar),
            view: na::zero(),
            proj: na::zero(),
            proj_view: na::zero(),
            inverse_proj_view: na::zero(),
            last_cursor_pos: na::zero(),
            up_axis: Vector3::y(),
        };

        res.look_at(eye, at);

        res
    }

    /// The point the arc-ball is looking at.
    pub fn at(&self) -> Point3<f32> {
        self.at
    }

    /// Get a mutable reference to the point the camera is looking at.
    pub fn set_at(&mut self, at: Point3<f32>) {
        self.at = at;
        self.update_projviews();
    }

    /// The arc-ball camera `yaw`.
    pub fn yaw(&self) -> f32 {
        self.yaw
    }

    /// Sets the camera `yaw`. Change this to modify the rotation along the `up` axis.
    pub fn set_yaw(&mut self, yaw: f32) {
        self.yaw = yaw;

        self.update_restrictions();
        self.update_projviews();
    }

    /// The arc-ball camera `pitch`.
    pub fn pitch(&self) -> f32 {
        self.pitch
    }

    /// Sets the camera `pitch`.
    pub fn set_pitch(&mut self, pitch: f32) {
        self.pitch = pitch;

        self.update_restrictions();
        self.update_projviews();
    }

    /// The distance from the camera position to its view point.
    pub fn dist(&self) -> f32 {
        self.dist
    }

    /// Move the camera such that it is at a given distance from the view point.
    pub fn set_dist(&mut self, dist: f32) {
        self.dist = dist;

        self.update_restrictions();
        self.update_projviews();
    }

    /// The minimum distance from the camera position to its view point.
    pub fn min_dist(&self) -> f32 {
        self.min_dist
    }

    /// Set the minimum distance from the camera position to its view point.
    pub fn set_min_dist(&mut self, min_dist: f32) {
        self.min_dist = min_dist;
    }

    /// The maximum distance from the camera position to its view point.
    pub fn max_dist(&self) -> f32 {
        self.max_dist
    }

    /// Set the maximum distance from the camera position to its view point.
    pub fn set_max_dist(&mut self, max_dist: f32) {
        self.max_dist = max_dist;
    }

    /// Move and orient the camera such that it looks at a specific point.
    pub fn look_at(&mut self, eye: Point3<f32>, at: Point3<f32>) {
        let dist = (eye - at).norm();
        let pitch = ((eye.y - at.y) / dist).acos();
        let yaw = (eye.z - at.z).atan2(eye.x - at.x);

        self.at = at;
        self.dist = dist;
        self.yaw = yaw;
        self.pitch = pitch;

        self.update_restrictions();
        self.update_projviews();
    }

    /// Transformation applied by the camera without perspective.
    fn update_restrictions(&mut self) {
        if self.dist < self.min_dist {
            self.dist = self.min_dist
        }

        if self.dist > self.max_dist {
            self.dist = self.max_dist
        }

        if self.pitch <= 0.01 {
            self.pitch = 0.01
        }

        let _pi: f32 = f32::consts::PI;
        if self.pitch > _pi - 0.01 {
            self.pitch = _pi - 0.01
        }
    }

    /// The button used to rotate the ArcBall camera.
    pub fn rotate_button(&self) -> Option<MouseButton> {
        self.rotate_button
    }

    /// Set the button used to rotate the ArcBall camera.
    /// Use None to disable rotation.
    pub fn rebind_rotate_button(&mut self, new_button: Option<MouseButton>) {
        self.rotate_button = new_button;
    }

    /// The button used to drag the ArcBall camera.
    pub fn drag_button(&self) -> Option<MouseButton> {
        self.drag_button
    }

    /// Set the button used to drag the ArcBall camera.
    /// Use None to disable dragging.
    pub fn rebind_drag_button(&mut self, new_button: Option<MouseButton>) {
        self.drag_button = new_button;
    }

    /// The key used to reset the ArcBall camera.
    pub fn reset_key(&self) -> Option<Key> {
        self.reset_key
    }

    /// Set the key used to reset the ArcBall camera.
    /// Use None to disable reset.
    pub fn rebind_reset_key(&mut self, new_key: Option<Key>) {
        self.reset_key = new_key;
    }

    fn handle_left_button_displacement(&mut self, dpos: &Vector2<f32>) {
        self.yaw = self.yaw + dpos.x * self.yaw_step;
        self.pitch = self.pitch - dpos.y * self.pitch_step;

        self.update_restrictions();
        self.update_projviews();
    }

    fn handle_right_button_displacement(&mut self, dpos: &Vector2<f32>) {
        let eye = self.eye();
        let dir = (self.at - eye).normalize();
        let tangent = Vector3::y().cross(&dir).normalize();
        let bitangent = dir.cross(&tangent);
        let mult = self.dist / 1000.0;

        self.at = self.at + tangent * (dpos.x * mult) + bitangent * (dpos.y * mult);
        self.update_projviews();
    }

    fn handle_scroll(&mut self, off: f32) {
        self.dist = self.dist + self.dist_step * (off) / 120.0;
        self.update_restrictions();
        self.update_projviews();
    }

    fn update_projviews(&mut self) {
        self.proj = *self.projection.as_matrix();
        self.view = self.view_transform().to_homogeneous();
        self.proj_view = self.proj * self.view;
        self.inverse_proj_view = self.proj_view.try_inverse().unwrap();
    }

    /// Sets the up vector of this camera.
    #[inline]
    pub fn set_up_axis(&mut self, up_axis: Vector3<f32>) {
        self.up_axis = up_axis;
    }

}

impl Camera for ArcBall {
    fn clip_planes(&self) -> (f32, f32) {
        (self.projection.znear(), self.projection.zfar())
    }

    fn view_transform(&self) -> Isometry3<f32> {
        Isometry3::look_at_rh(&self.eye(), &self.at,  &self.up_axis)
    }

    fn eye(&self) -> Point3<f32> {
        let px = self.at.x + self.dist * self.yaw.cos() * self.pitch.sin();
        let py = self.at.y + self.dist * self.pitch.cos();
        let pz = self.at.z + self.dist * self.yaw.sin() * self.pitch.sin();

        Point3::new(px, py, pz)
    }

    fn handle_event(&mut self, canvas: &Canvas, event: &WindowEvent) {
        match *event {
            WindowEvent::CursorPos(x, y, _) => {
                let curr_pos = Vector2::new(x as f32, y as f32);

                if let Some(rotate_button) = self.rotate_button {
                    if canvas.get_mouse_button(rotate_button) == Action::Press {
                        let dpos = curr_pos - self.last_cursor_pos;
                        self.handle_left_button_displacement(&dpos)
                    }
                }

                if let Some(drag_button) = self.drag_button {
                    if canvas.get_mouse_button(drag_button) == Action::Press {
                        let dpos = curr_pos - self.last_cursor_pos;
                        self.handle_right_button_displacement(&dpos)
                    }
                }

                self.last_cursor_pos = curr_pos;
            }
            WindowEvent::Key(key, Action::Press, _) if Some(key) == self.reset_key => {
                self.at = Point3::origin();
                self.update_projviews();
            }
            WindowEvent::Scroll(_, off, _) => self.handle_scroll(off as f32),
            WindowEvent::FramebufferSize(w, h) => {
                self.projection.set_aspect(w as f32 / h as f32);
                self.update_projviews();
            }
            _ => {}
        }
    }

    #[inline]
    fn upload(
        &self,
        _: usize,
        proj: &mut ShaderUniform<Matrix4<f32>>,
        view: &mut ShaderUniform<Matrix4<f32>>,
    ) {
        proj.upload(&self.proj);
        view.upload(&self.view);
    }

    fn transformation(&self) -> Matrix4<f32> {
        self.proj_view
    }

    fn inverse_transformation(&self) -> Matrix4<f32> {
        self.inverse_proj_view
    }

    fn update(&mut self, _: &Canvas) {}
}
<commit_msg>Add min/max pitch settings to arcball camera<commit_after>use camera::Camera;
use event::{Action, Key, MouseButton, WindowEvent};
use na::{self, Isometry3, Matrix4, Perspective3, Point3, Vector2, Vector3};
use resource::ShaderUniform;
use std::f32;
use window::Canvas;

/// Arc-ball camera mode.
///
/// An arc-ball camera is a camera rotating around a fixed point (the focus point) and always
/// looking at it. The following inputs are handled:
///
/// * Left button press + drag - rotates the camera around the focus point
/// * Right button press + drag - translates the focus point on the plane orthogonal to the view
/// direction
/// * Scroll in/out - zoom in/out
/// * Enter key - set the focus point to the origin
#[derive(Clone, Debug)]
pub struct ArcBall {
    /// The focus point.
    at: Point3<f32>,
    /// Yaw of the camera (rotation along the y axis).
    yaw: f32,
    /// Pitch of the camera (rotation along the x axis).
    pitch: f32,
    /// Distance from the camera to the `at` focus point.
    dist: f32,
    /// Minimum distance from the camera to the `at` focus point.
    min_dist: f32,
    /// Maximum distance from the camera to the `at` focus point.
    max_dist: f32,

    /// Increment of the yaw per unit mouse movement. The default value is 0.005.
    yaw_step: f32,
    /// Increment of the pitch per unit mouse movement. The default value is 0.005.
    pitch_step: f32,
    /// Minimum pitch of the camera.
    min_pitch: f32,
    /// Maximum pitch ofthe camera.
    max_pitch: f32,
    /// Increment of the distance per unit scrolling. The default value is 40.0.
    dist_step: f32,
    rotate_button: Option<MouseButton>,
    drag_button: Option<MouseButton>,
    reset_key: Option<Key>,

    projection: Perspective3<f32>,
    view: Matrix4<f32>,
    proj: Matrix4<f32>,
    proj_view: Matrix4<f32>,
    inverse_proj_view: Matrix4<f32>,
    last_cursor_pos: Vector2<f32>,
    up_axis: Vector3<f32>,
}

impl ArcBall {
    /// Create a new arc-ball camera.
    pub fn new(eye: Point3<f32>, at: Point3<f32>) -> ArcBall {
        ArcBall::new_with_frustrum(f32::consts::PI / 4.0, 0.1, 1024.0, eye, at)
    }

    /// Creates a new arc ball camera with default sensitivity values.
    pub fn new_with_frustrum(
        fov: f32,
        znear: f32,
        zfar: f32,
        eye: Point3<f32>,
        at: Point3<f32>,
    ) -> ArcBall {
        let mut res = ArcBall {
            at: Point3::new(0.0, 0.0, 0.0),
            yaw: 0.0,
            pitch: 0.0,
            dist: 0.0,
            min_dist: 0.00001,
            max_dist: std::f32::MAX,
            yaw_step: 0.005,
            pitch_step: 0.005,
            min_pitch: 0.01,
            max_pitch: std::f32::consts::PI - 0.01,
            dist_step: 40.0,
            rotate_button: Some(MouseButton::Button1),
            drag_button: Some(MouseButton::Button2),
            reset_key: Some(Key::Return),
            projection: Perspective3::new(800.0 / 600.0, fov, znear, zfar),
            view: na::zero(),
            proj: na::zero(),
            proj_view: na::zero(),
            inverse_proj_view: na::zero(),
            last_cursor_pos: na::zero(),
            up_axis: Vector3::y(),
        };

        res.look_at(eye, at);

        res
    }

    /// The point the arc-ball is looking at.
    pub fn at(&self) -> Point3<f32> {
        self.at
    }

    /// Get a mutable reference to the point the camera is looking at.
    pub fn set_at(&mut self, at: Point3<f32>) {
        self.at = at;
        self.update_projviews();
    }

    /// The arc-ball camera `yaw`.
    pub fn yaw(&self) -> f32 {
        self.yaw
    }

    /// Sets the camera `yaw`. Change this to modify the rotation along the `up` axis.
    pub fn set_yaw(&mut self, yaw: f32) {
        self.yaw = yaw;

        self.update_restrictions();
        self.update_projviews();
    }

    /// The arc-ball camera `pitch`.
    pub fn pitch(&self) -> f32 {
        self.pitch
    }

    /// Sets the camera `pitch`.
    pub fn set_pitch(&mut self, pitch: f32) {
        self.pitch = pitch;

        self.update_restrictions();
        self.update_projviews();
    }

    /// The minimum pitch of the camera.
    pub fn min_pitch(&self) -> f32 {
        self.min_pitch
    }

    /// Set the minimum pitch of the camera.
    pub fn set_min_pitch(&mut self, min_pitch: f32) {
        self.min_pitch = min_pitch;
    }

    /// The maximum pitch of the camera.
    pub fn max_pitch(&self) -> f32 {
        self.max_pitch
    }

    /// Set the maximum pitch of the camera.
    pub fn set_max_pitch(&mut self, max_pitch: f32) {
        self.max_pitch = max_pitch;
    }

    /// The distance from the camera position to its view point.
    pub fn dist(&self) -> f32 {
        self.dist
    }

    /// Move the camera such that it is at a given distance from the view point.
    pub fn set_dist(&mut self, dist: f32) {
        self.dist = dist;

        self.update_restrictions();
        self.update_projviews();
    }

    /// The minimum distance from the camera position to its view point.
    pub fn min_dist(&self) -> f32 {
        self.min_dist
    }

    /// Set the minimum distance from the camera position to its view point.
    pub fn set_min_dist(&mut self, min_dist: f32) {
        self.min_dist = min_dist;
    }

    /// The maximum distance from the camera position to its view point.
    pub fn max_dist(&self) -> f32 {
        self.max_dist
    }

    /// Set the maximum distance from the camera position to its view point.
    pub fn set_max_dist(&mut self, max_dist: f32) {
        self.max_dist = max_dist;
    }

    /// Move and orient the camera such that it looks at a specific point.
    pub fn look_at(&mut self, eye: Point3<f32>, at: Point3<f32>) {
        let dist = (eye - at).norm();
        let pitch = ((eye.y - at.y) / dist).acos();
        let yaw = (eye.z - at.z).atan2(eye.x - at.x);

        self.at = at;
        self.dist = dist;
        self.yaw = yaw;
        self.pitch = pitch;

        self.update_restrictions();
        self.update_projviews();
    }

    /// Transformation applied by the camera without perspective.
    fn update_restrictions(&mut self) {
        if self.dist < self.min_dist {
            self.dist = self.min_dist
        }

        if self.dist > self.max_dist {
            self.dist = self.max_dist
        }

        if self.pitch <= self.min_pitch {
            self.pitch = self.min_pitch
        }

        if self.pitch > self.max_pitch {
            self.pitch = self.max_pitch
        }
    }

    /// The button used to rotate the ArcBall camera.
    pub fn rotate_button(&self) -> Option<MouseButton> {
        self.rotate_button
    }

    /// Set the button used to rotate the ArcBall camera.
    /// Use None to disable rotation.
    pub fn rebind_rotate_button(&mut self, new_button: Option<MouseButton>) {
        self.rotate_button = new_button;
    }

    /// The button used to drag the ArcBall camera.
    pub fn drag_button(&self) -> Option<MouseButton> {
        self.drag_button
    }

    /// Set the button used to drag the ArcBall camera.
    /// Use None to disable dragging.
    pub fn rebind_drag_button(&mut self, new_button: Option<MouseButton>) {
        self.drag_button = new_button;
    }

    /// The key used to reset the ArcBall camera.
    pub fn reset_key(&self) -> Option<Key> {
        self.reset_key
    }

    /// Set the key used to reset the ArcBall camera.
    /// Use None to disable reset.
    pub fn rebind_reset_key(&mut self, new_key: Option<Key>) {
        self.reset_key = new_key;
    }

    fn handle_left_button_displacement(&mut self, dpos: &Vector2<f32>) {
        self.yaw = self.yaw + dpos.x * self.yaw_step;
        self.pitch = self.pitch - dpos.y * self.pitch_step;

        self.update_restrictions();
        self.update_projviews();
    }

    fn handle_right_button_displacement(&mut self, dpos: &Vector2<f32>) {
        let eye = self.eye();
        let dir = (self.at - eye).normalize();
        let tangent = Vector3::y().cross(&dir).normalize();
        let bitangent = dir.cross(&tangent);
        let mult = self.dist / 1000.0;

        self.at = self.at + tangent * (dpos.x * mult) + bitangent * (dpos.y * mult);
        self.update_projviews();
    }

    fn handle_scroll(&mut self, off: f32) {
        self.dist = self.dist + self.dist_step * (off) / 120.0;
        self.update_restrictions();
        self.update_projviews();
    }

    fn update_projviews(&mut self) {
        self.proj = *self.projection.as_matrix();
        self.view = self.view_transform().to_homogeneous();
        self.proj_view = self.proj * self.view;
        self.inverse_proj_view = self.proj_view.try_inverse().unwrap();
    }

    /// Sets the up vector of this camera.
    #[inline]
    pub fn set_up_axis(&mut self, up_axis: Vector3<f32>) {
        self.up_axis = up_axis;
    }

}

impl Camera for ArcBall {
    fn clip_planes(&self) -> (f32, f32) {
        (self.projection.znear(), self.projection.zfar())
    }

    fn view_transform(&self) -> Isometry3<f32> {
        Isometry3::look_at_rh(&self.eye(), &self.at,  &self.up_axis)
    }

    fn eye(&self) -> Point3<f32> {
        let px = self.at.x + self.dist * self.yaw.cos() * self.pitch.sin();
        let py = self.at.y + self.dist * self.pitch.cos();
        let pz = self.at.z + self.dist * self.yaw.sin() * self.pitch.sin();

        Point3::new(px, py, pz)
    }

    fn handle_event(&mut self, canvas: &Canvas, event: &WindowEvent) {
        match *event {
            WindowEvent::CursorPos(x, y, _) => {
                let curr_pos = Vector2::new(x as f32, y as f32);

                if let Some(rotate_button) = self.rotate_button {
                    if canvas.get_mouse_button(rotate_button) == Action::Press {
                        let dpos = curr_pos - self.last_cursor_pos;
                        self.handle_left_button_displacement(&dpos)
                    }
                }

                if let Some(drag_button) = self.drag_button {
                    if canvas.get_mouse_button(drag_button) == Action::Press {
                        let dpos = curr_pos - self.last_cursor_pos;
                        self.handle_right_button_displacement(&dpos)
                    }
                }

                self.last_cursor_pos = curr_pos;
            }
            WindowEvent::Key(key, Action::Press, _) if Some(key) == self.reset_key => {
                self.at = Point3::origin();
                self.update_projviews();
            }
            WindowEvent::Scroll(_, off, _) => self.handle_scroll(off as f32),
            WindowEvent::FramebufferSize(w, h) => {
                self.projection.set_aspect(w as f32 / h as f32);
                self.update_projviews();
            }
            _ => {}
        }
    }

    #[inline]
    fn upload(
        &self,
        _: usize,
        proj: &mut ShaderUniform<Matrix4<f32>>,
        view: &mut ShaderUniform<Matrix4<f32>>,
    ) {
        proj.upload(&self.proj);
        view.upload(&self.view);
    }

    fn transformation(&self) -> Matrix4<f32> {
        self.proj_view
    }

    fn inverse_transformation(&self) -> Matrix4<f32> {
        self.inverse_proj_view
    }

    fn update(&mut self, _: &Canvas) {}
}
<|endoftext|>


<commit_before>use std::iter::from_fn;

use turtle::{choose, random, Color, Turtle};

fn main() {
    // Parameters to play around with for changing the character of the created drawing.
    let width = 800;
    let height = 600;
    let row_count = 3;
    let col_count = 4;
    let color_count = 7;

    let mut turtle = ArtisticTurtle::new(width, height, row_count, col_count, color_count);
    turtle.draw();
}

/// A special kind of turtle that is specialized in creating drawings of colorful triangles.
struct ArtisticTurtle {
    turtle: Turtle,
    row_count: u32,
    col_count: u32,
    row_height: f64,
    col_width: f64,
    colors: Vec<Color>,
}

impl ArtisticTurtle {
    /// Create a new turtle using the given parameters.
    /// `width`: total width of the drawing
    /// `height`: total height of the drawing
    /// `row_count`: number of rows of triangles to be created
    /// `col_count`: number of columns per row to be created
    /// `color_count`: number of different colors to use
    fn new(width: u32, height: u32, row_count: u32, col_count: u32, color_count: usize) -> Self {
        // Create and prepare the turtle.
        let mut turtle = Turtle::new();
        turtle.set_speed("instant");
        turtle.pen_up();
        turtle.drawing_mut().set_size([width, height]);

        // Move turtle to the upper left corner of the drawing.
        let size = turtle.drawing().size();
        let x_start = size.width / 2;
        let y_start = size.height / 2;
        turtle.go_to([f64::from(x_start) * -1.0, f64::from(y_start)]);
        turtle.set_speed(20);

        // Calculate height and width of the triangles.
        let row_height = f64::from(size.height) / f64::from(row_count);
        let col_width = f64::from(size.width) / f64::from(col_count);

        // Prepare a set of random colors to randomly choose from when drawing.
        let colors: Vec<Color> = from_fn(|| Some(random())).take(color_count).collect();

        Self {
            turtle,
            row_count,
            col_count,
            row_height,
            col_width,
            colors,
        }
    }

    /// Draw a single triangle by drawing two sides and filling them with a random color
    /// which creates the third side of the triangle along the way.
    /// Note: Even though the turtle is always turning right in this method, this movement
    /// can also result in a left turn (depending on the angle chosen).
    fn draw_triangle(&mut self, angle: f64) {
        // This call to unwrap() is always safe because the color slice will always be non-empty.
        let color = choose(&self.colors).cloned().unwrap();
        self.turtle.set_fill_color(color);
        self.turtle.begin_fill();

        self.turtle.right(angle);
        self.turtle.forward(self.col_width);

        self.turtle.right(angle);
        self.turtle.forward(self.row_height);

        self.turtle.end_fill();
    }

    /// Draw a single row of triangles in two runs:
    /// 1. Create triangles from left to right.
    /// 2. Turn around and fill in triangles from right to left.
    fn draw_row(&mut self) {
        // Create an endless loop over the angles of 90 and 270 degrees
        // (corresponds to moving right and left, respectively).
        let angles = vec![90.0, 270.0];
        let angle_cycle = &mut angles.iter().cycle();

        // Create triangles from left to right.
        angle_cycle.take(self.col_count as usize).for_each(|angle| self.draw_triangle(*angle));

        // Skip one angle so that we have the correct angle when turning around.
        angle_cycle.next();

        // Fill in triangles from right to left to complete the row.
        angle_cycle.take(self.col_count as usize).for_each(|angle| self.draw_triangle(*angle));

        // Reset position to prepare for the next row.
        self.turtle.right(180.0);
        self.turtle.forward(self.row_height);
        self.turtle.left(180.0);
    }

    /// Create a drawing consisting of rows of triangles in different colors.
    fn draw(&mut self) {
        for _ in 0..self.row_count {
            self.draw_row();
        }
        self.turtle.hide();
    }
}
<commit_msg>Improve draw_row method<commit_after>use std::iter::from_fn;

use turtle::{choose, random, Color, Turtle};

fn main() {
    // Parameters to play around with for changing the character of the created drawing.
    let width = 800;
    let height = 600;
    let row_count = 3;
    let col_count = 4;
    let color_count = 7;

    let mut turtle = ArtisticTurtle::new(width, height, row_count, col_count, color_count);
    turtle.draw();
}

/// A special kind of turtle that is specialized in creating drawings of colorful triangles.
struct ArtisticTurtle {
    turtle: Turtle,
    row_count: u32,
    col_count: u32,
    row_height: f64,
    col_width: f64,
    colors: Vec<Color>,
}

impl ArtisticTurtle {
    /// Create a new turtle using the given parameters.
    /// `width`: total width of the drawing
    /// `height`: total height of the drawing
    /// `row_count`: number of rows of triangles to be created
    /// `col_count`: number of columns per row to be created
    /// `color_count`: number of different colors to use
    fn new(width: u32, height: u32, row_count: u32, col_count: u32, color_count: usize) -> Self {
        // Create and prepare the turtle.
        let mut turtle = Turtle::new();
        turtle.set_speed("instant");
        turtle.pen_up();
        turtle.drawing_mut().set_size([width, height]);

        // Move turtle to the upper left corner of the drawing.
        let size = turtle.drawing().size();
        let x_start = size.width / 2;
        let y_start = size.height / 2;
        turtle.go_to([f64::from(x_start) * -1.0, f64::from(y_start)]);
        turtle.set_speed(20);

        // Calculate height and width of the triangles.
        let row_height = f64::from(size.height) / f64::from(row_count);
        let col_width = f64::from(size.width) / f64::from(col_count);

        // Prepare a set of random colors to randomly choose from when drawing.
        let colors: Vec<Color> = from_fn(|| Some(random())).take(color_count).collect();

        Self {
            turtle,
            row_count,
            col_count,
            row_height,
            col_width,
            colors,
        }
    }

    /// Draw a single triangle by drawing two sides and filling them with a random color
    /// which creates the third side of the triangle along the way.
    /// Note: Even though the turtle is always turning right in this method, this movement
    /// can also result in a left turn (depending on the angle chosen).
    fn draw_triangle(&mut self, angle: f64) {
        // This call to unwrap() is always safe because the color slice will always be non-empty.
        let color = choose(&self.colors).cloned().unwrap();
        self.turtle.set_fill_color(color);
        self.turtle.begin_fill();

        self.turtle.right(angle);
        self.turtle.forward(self.col_width);

        self.turtle.right(angle);
        self.turtle.forward(self.row_height);

        self.turtle.end_fill();
    }

    /// Draw a single row of triangles in two runs:
    /// 1. Create triangles from left to right.
    /// 2. Turn around and fill in triangles from right to left.
    fn draw_row(&mut self) {
        // Create an endless loop over the angles of 90 and 270 degrees
        // (corresponds to moving right and left, respectively).
        // Need `&mut` so the value does not move when we call `take()` twice
        let angles = &mut [90.0, 270.0].into_iter().cycle();

        // Create triangles from left to right.
        for angle in angles.take(self.col_count as usize) {
            self.draw_triangle(*angle);
        }

        // Skip one angle so that we have the correct angle when turning around.
        angles.next();

        // Fill in triangles from right to left to complete the row.
        for angle in angles.take(self.col_count as usize) {
            self.draw_triangle(*angle);
        }

        // Reset position to prepare for the next row.
        self.turtle.right(180.0);
        self.turtle.forward(self.row_height);
        self.turtle.left(180.0);
    }

    /// Create a drawing consisting of rows of triangles in different colors.
    fn draw(&mut self) {
        for _ in 0..self.row_count {
            self.draw_row();
        }
        self.turtle.hide();
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::str;

fn main() {
    // Avoid unnecessary re-building.
    println!("cargo:rerun-if-changed=build.rs");

    let (rustc_minor_ver, is_nightly) = rustc_minor_nightly().expect("Failed to get rustc version");
    let rustc_dep_of_std = env::var("CARGO_FEATURE_RUSTC_DEP_OF_STD").is_ok();
    let align_cargo_feature = env::var("CARGO_FEATURE_ALIGN").is_ok();
    let const_extern_fn_cargo_feature = env::var("CARGO_FEATURE_CONST_EXTERN_FN").is_ok();
    let libc_ci = env::var("LIBC_CI").is_ok();

    if env::var("CARGO_FEATURE_USE_STD").is_ok() {
        println!(
            "cargo:warning=\"libc's use_std cargo feature is deprecated since libc 0.2.55; \
             please consider using the `std` cargo feature instead\""
        );
    }

    // The ABI of libc used by libstd is backward compatible with FreeBSD 10.
    // The ABI of libc from crates.io is backward compatible with FreeBSD 11.
    //
    // On CI, we detect the actual FreeBSD version and match its ABI exactly,
    // running tests to ensure that the ABI is correct.
    match which_freebsd() {
        Some(10) if libc_ci || rustc_dep_of_std => {
            println!("cargo:rustc-cfg=freebsd10")
        }
        Some(11) if libc_ci => println!("cargo:rustc-cfg=freebsd11"),
        Some(12) if libc_ci => println!("cargo:rustc-cfg=freebsd12"),
        Some(13) if libc_ci => println!("cargo:rustc-cfg=freebsd13"),
        Some(14) if libc_ci => println!("cargo:rustc-cfg=freebsd14"),
        Some(_) | None => println!("cargo:rustc-cfg=freebsd11"),
    }

    // On CI: deny all warnings
    if libc_ci {
        println!("cargo:rustc-cfg=libc_deny_warnings");
    }

    // Rust >= 1.15 supports private module use:
    if rustc_minor_ver >= 15 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_priv_mod_use");
    }

    // Rust >= 1.19 supports unions:
    if rustc_minor_ver >= 19 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_union");
    }

    // Rust >= 1.24 supports const mem::size_of:
    if rustc_minor_ver >= 24 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_const_size_of");
    }

    // Rust >= 1.25 supports repr(align):
    if rustc_minor_ver >= 25 || rustc_dep_of_std || align_cargo_feature {
        println!("cargo:rustc-cfg=libc_align");
    }

    // Rust >= 1.26 supports i128 and u128:
    if rustc_minor_ver >= 26 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_int128");
    }

    // Rust >= 1.30 supports `core::ffi::c_void`, so libc can just re-export it.
    // Otherwise, it defines an incompatible type to retaining
    // backwards-compatibility.
    if rustc_minor_ver >= 30 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_core_cvoid");
    }

    // Rust >= 1.33 supports repr(packed(N)) and cfg(target_vendor).
    if rustc_minor_ver >= 33 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_packedN");
        println!("cargo:rustc-cfg=libc_cfg_target_vendor");
    }

    // Rust >= 1.40 supports #[non_exhaustive].
    if rustc_minor_ver >= 40 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_non_exhaustive");
    }

    if rustc_minor_ver >= 51 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_ptr_addr_of");
    }

    // Rust >= 1.37.0 allows underscores as anonymous constant names.
    if rustc_minor_ver >= 37 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_underscore_const_names");
    }

    // #[thread_local] is currently unstable
    if rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_thread_local");
    }

    // Rust >= 1.62.0 allows to use `const_extern_fn` for "Rust" and "C".
    if rustc_minor_ver >= 62 {
        println!("cargo:rustc-cfg=libc_const_extern_fn");
    } else {
        // Rust < 1.62.0 requires a crate feature and feature gate.
        if const_extern_fn_cargo_feature {
            if !is_nightly || rustc_minor_ver < 40 {
                panic!("const-extern-fn requires a nightly compiler >= 1.40");
            }
            println!("cargo:rustc-cfg=libc_const_extern_fn_unstable");
            println!("cargo:rustc-cfg=libc_const_extern_fn");
        }
    }
}

fn rustc_minor_nightly() -> Option<(u32, bool)> {
    macro_rules! otry {
        ($e:expr) => {
            match $e {
                Some(e) => e,
                None => return None,
            }
        };
    }

    let rustc = otry!(env::var_os("RUSTC"));
    let output = otry!(Command::new(rustc).arg("--version").output().ok());
    let version = otry!(str::from_utf8(&output.stdout).ok());
    let mut pieces = version.split('.');

    if pieces.next() != Some("rustc 1") {
        return None;
    }

    let minor = pieces.next();

    // If `rustc` was built from a tarball, its version string
    // will have neither a git hash nor a commit date
    // (e.g. "rustc 1.39.0"). Treat this case as non-nightly,
    // since a nightly build should either come from CI
    // or a git checkout
    let nightly_raw = otry!(pieces.next()).split('-').nth(1);
    let nightly = nightly_raw
        .map(|raw| raw.starts_with("dev") || raw.starts_with("nightly"))
        .unwrap_or(false);
    let minor = otry!(otry!(minor).parse().ok());

    Some((minor, nightly))
}

fn which_freebsd() -> Option<i32> {
    let output = std::process::Command::new("freebsd-version").output().ok();
    if output.is_none() {
        return None;
    }
    let output = output.unwrap();
    if !output.status.success() {
        return None;
    }

    let stdout = String::from_utf8(output.stdout).ok();
    if stdout.is_none() {
        return None;
    }
    let stdout = stdout.unwrap();

    match &stdout {
        s if s.starts_with("10") => Some(10),
        s if s.starts_with("11") => Some(11),
        s if s.starts_with("12") => Some(12),
        s if s.starts_with("13") => Some(13),
        s if s.starts_with("14") => Some(14),
        _ => None,
    }
}
<commit_msg>Report the actual error when failing to get the rustc version<commit_after>use std::env;
use std::process::Command;
use std::str;

fn main() {
    // Avoid unnecessary re-building.
    println!("cargo:rerun-if-changed=build.rs");

    let (rustc_minor_ver, is_nightly) = rustc_minor_nightly();
    let rustc_dep_of_std = env::var("CARGO_FEATURE_RUSTC_DEP_OF_STD").is_ok();
    let align_cargo_feature = env::var("CARGO_FEATURE_ALIGN").is_ok();
    let const_extern_fn_cargo_feature = env::var("CARGO_FEATURE_CONST_EXTERN_FN").is_ok();
    let libc_ci = env::var("LIBC_CI").is_ok();

    if env::var("CARGO_FEATURE_USE_STD").is_ok() {
        println!(
            "cargo:warning=\"libc's use_std cargo feature is deprecated since libc 0.2.55; \
             please consider using the `std` cargo feature instead\""
        );
    }

    // The ABI of libc used by libstd is backward compatible with FreeBSD 10.
    // The ABI of libc from crates.io is backward compatible with FreeBSD 11.
    //
    // On CI, we detect the actual FreeBSD version and match its ABI exactly,
    // running tests to ensure that the ABI is correct.
    match which_freebsd() {
        Some(10) if libc_ci || rustc_dep_of_std => {
            println!("cargo:rustc-cfg=freebsd10")
        }
        Some(11) if libc_ci => println!("cargo:rustc-cfg=freebsd11"),
        Some(12) if libc_ci => println!("cargo:rustc-cfg=freebsd12"),
        Some(13) if libc_ci => println!("cargo:rustc-cfg=freebsd13"),
        Some(14) if libc_ci => println!("cargo:rustc-cfg=freebsd14"),
        Some(_) | None => println!("cargo:rustc-cfg=freebsd11"),
    }

    // On CI: deny all warnings
    if libc_ci {
        println!("cargo:rustc-cfg=libc_deny_warnings");
    }

    // Rust >= 1.15 supports private module use:
    if rustc_minor_ver >= 15 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_priv_mod_use");
    }

    // Rust >= 1.19 supports unions:
    if rustc_minor_ver >= 19 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_union");
    }

    // Rust >= 1.24 supports const mem::size_of:
    if rustc_minor_ver >= 24 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_const_size_of");
    }

    // Rust >= 1.25 supports repr(align):
    if rustc_minor_ver >= 25 || rustc_dep_of_std || align_cargo_feature {
        println!("cargo:rustc-cfg=libc_align");
    }

    // Rust >= 1.26 supports i128 and u128:
    if rustc_minor_ver >= 26 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_int128");
    }

    // Rust >= 1.30 supports `core::ffi::c_void`, so libc can just re-export it.
    // Otherwise, it defines an incompatible type to retaining
    // backwards-compatibility.
    if rustc_minor_ver >= 30 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_core_cvoid");
    }

    // Rust >= 1.33 supports repr(packed(N)) and cfg(target_vendor).
    if rustc_minor_ver >= 33 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_packedN");
        println!("cargo:rustc-cfg=libc_cfg_target_vendor");
    }

    // Rust >= 1.40 supports #[non_exhaustive].
    if rustc_minor_ver >= 40 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_non_exhaustive");
    }

    if rustc_minor_ver >= 51 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_ptr_addr_of");
    }

    // Rust >= 1.37.0 allows underscores as anonymous constant names.
    if rustc_minor_ver >= 37 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_underscore_const_names");
    }

    // #[thread_local] is currently unstable
    if rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_thread_local");
    }

    // Rust >= 1.62.0 allows to use `const_extern_fn` for "Rust" and "C".
    if rustc_minor_ver >= 62 {
        println!("cargo:rustc-cfg=libc_const_extern_fn");
    } else {
        // Rust < 1.62.0 requires a crate feature and feature gate.
        if const_extern_fn_cargo_feature {
            if !is_nightly || rustc_minor_ver < 40 {
                panic!("const-extern-fn requires a nightly compiler >= 1.40");
            }
            println!("cargo:rustc-cfg=libc_const_extern_fn_unstable");
            println!("cargo:rustc-cfg=libc_const_extern_fn");
        }
    }
}

fn rustc_minor_nightly() -> (u32, bool) {
    macro_rules! otry {
        ($e:expr) => {
            match $e {
                Some(e) => e,
                None => panic!("Failed to get rustc version"),
            }
        };
    }

    let rustc = otry!(env::var_os("RUSTC"));
    let output = Command::new(rustc)
        .arg("--version")
        .output()
        .ok()
        .expect("Failed to get rustc version");
    let version = otry!(str::from_utf8(&output.stdout).ok());
    let mut pieces = version.split('.');

    if pieces.next() != Some("rustc 1") {
        panic!("Failed to get rustc version");
    }

    let minor = pieces.next();

    // If `rustc` was built from a tarball, its version string
    // will have neither a git hash nor a commit date
    // (e.g. "rustc 1.39.0"). Treat this case as non-nightly,
    // since a nightly build should either come from CI
    // or a git checkout
    let nightly_raw = otry!(pieces.next()).split('-').nth(1);
    let nightly = nightly_raw
        .map(|raw| raw.starts_with("dev") || raw.starts_with("nightly"))
        .unwrap_or(false);
    let minor = otry!(otry!(minor).parse().ok());

    (minor, nightly)
}

fn which_freebsd() -> Option<i32> {
    let output = std::process::Command::new("freebsd-version").output().ok();
    if output.is_none() {
        return None;
    }
    let output = output.unwrap();
    if !output.status.success() {
        return None;
    }

    let stdout = String::from_utf8(output.stdout).ok();
    if stdout.is_none() {
        return None;
    }
    let stdout = stdout.unwrap();

    match &stdout {
        s if s.starts_with("10") => Some(10),
        s if s.starts_with("11") => Some(11),
        s if s.starts_with("12") => Some(12),
        s if s.starts_with("13") => Some(13),
        s if s.starts_with("14") => Some(14),
        _ => None,
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[cfg(windows)]
extern crate embed_resource;
#[cfg(windows)]
extern crate tempdir;
#[cfg(windows)]
extern crate reqwest;
#[cfg(windows)]
extern crate zip;

#[cfg(windows)]
use tempdir::TempDir;

extern crate gl_generator;

use gl_generator::{Api, Fallbacks, GlobalGenerator, Profile, Registry};

use std::env;
use std::fs::File;
use std::path::Path;

#[cfg(windows)]
use std::io;
#[cfg(windows)]
use std::fs::OpenOptions;

#[cfg(windows)]
const WINPTY_PACKAGE_URL: &str = "https://www.nuget.org/api/v2/package/winpty.NET/0.4.2";

fn main() {
    let dest = env::var("OUT_DIR").unwrap();
    let mut file = File::create(&Path::new(&dest).join("gl_bindings.rs")).unwrap();

    Registry::new(
        Api::Gl,
        (4, 5),
        Profile::Core,
        Fallbacks::All,
        ["GL_ARB_blend_func_extended"],
    ).write_bindings(GlobalGenerator, &mut file)
        .unwrap();

    #[cfg(windows)]
    {
        embed_resource::compile("assets/windows/windows.rc");

        // Path is relative to target/{profile}/build/alacritty-HASH/out
        let file = Path::new(&env::var("OUT_DIR").unwrap()).join("../../../winpty-agent.exe");
        if !file.exists() {
            aquire_winpty_agent(&file);
        }
    }
}

#[cfg(windows)]
fn aquire_winpty_agent(out_path: &Path) {
    let tmp_dir = TempDir::new("alacritty_build").unwrap();

    let mut response = reqwest::get(WINPTY_PACKAGE_URL).unwrap();
    let mut file = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(tmp_dir.path().join("winpty_package.zip")).unwrap();

    io::copy(&mut response, &mut file).unwrap();

    let mut archive = zip::ZipArchive::new(file).unwrap();

    let target = match env::var("TARGET").unwrap().split("-").next().unwrap() {
        "x86_64" => "x86",
        "i386" => "x64",
        _ => panic!("architecture has no winpty binary")
    };

    let mut winpty_agent = archive.by_name(&format!("content/winpty/{}/winpty-agent.exe", target)).unwrap();

    io::copy(&mut winpty_agent, &mut File::create(out_path).unwrap()).unwrap();
}
<commit_msg>build(package): acquire latest winpty<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[cfg(windows)]
extern crate embed_resource;
#[cfg(windows)]
extern crate tempdir;
#[cfg(windows)]
extern crate reqwest;
#[cfg(windows)]
extern crate zip;

#[cfg(windows)]
use tempdir::TempDir;

extern crate gl_generator;

use gl_generator::{Api, Fallbacks, GlobalGenerator, Profile, Registry};

use std::env;
use std::fs::File;
use std::path::Path;

#[cfg(windows)]
use std::io;
#[cfg(windows)]
use std::fs::OpenOptions;

#[cfg(windows)]
const WINPTY_PACKAGE_URL: &str = "https://github.com/rprichard/winpty/releases/download/0.4.3/winpty-0.4.3-msvc2015.zip";

fn main() {
    let dest = env::var("OUT_DIR").unwrap();
    let mut file = File::create(&Path::new(&dest).join("gl_bindings.rs")).unwrap();

    Registry::new(
        Api::Gl,
        (4, 5),
        Profile::Core,
        Fallbacks::All,
        ["GL_ARB_blend_func_extended"],
    ).write_bindings(GlobalGenerator, &mut file)
        .unwrap();

    #[cfg(windows)]
    {
        embed_resource::compile("assets/windows/windows.rc");

        // Path is relative to target/{profile}/build/alacritty-HASH/out
        let file = Path::new(&env::var("OUT_DIR").unwrap()).join("../../../winpty-agent.exe");
        if !file.exists() {
            aquire_winpty_agent(&file);
        }
    }
}

#[cfg(windows)]
fn aquire_winpty_agent(out_path: &Path) {
    let tmp_dir = TempDir::new("alacritty_build").unwrap();

    let mut response = reqwest::get(WINPTY_PACKAGE_URL).unwrap();
    let mut file = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(tmp_dir.path().join("winpty_package.zip")).unwrap();

    io::copy(&mut response, &mut file).unwrap();

    let mut archive = zip::ZipArchive::new(file).unwrap();

    let target = match env::var("TARGET").unwrap().split("-").next().unwrap() {
        "x86_64" => "x64",
        "i386" => "ia32",
        _ => panic!("architecture has no winpty binary")
    };

    let mut winpty_agent = archive.by_name(&format!("{}/bin/winpty-agent.exe", target)).unwrap();

    io::copy(&mut winpty_agent, &mut File::create(out_path).unwrap()).unwrap();
}
<|endoftext|>


<commit_before>use std::env;
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;

struct Ignore;

impl<E> From<E> for Ignore
    where E: Error
{
    fn from(_: E) -> Ignore {
        Ignore
    }
}

fn main() {
    let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    File::create(out_dir.join("commit-info.txt"))
        .unwrap()
        .write_all(commit_info().as_bytes())
        .unwrap();
}

// Try to get hash and date of the last commit on a best effort basis. If anything goes wrong
// (git not installed or if this is not a git repository) just return an empty string.
fn commit_info() -> String {
    match (commit_hash(), commit_date()) {
        (Ok(hash), Ok(date)) => format!(" ({} {})", hash.trim_right(), date),
        _ => String::new(),
    }
}

fn commit_hash() -> Result<String, Ignore> {
    Ok(try!(String::from_utf8(try!(Command::new("git")
                                       .args(&["rev-parse", "--short", "HEAD"])
                                       .output())
                                  .stdout)))
}

fn commit_date() -> Result<String, Ignore> {
    Ok(try!(String::from_utf8(try!(Command::new("git")
                                       .args(&["log",
                                               "-1",
                                               "--date=short",
                                               "--pretty=format:%cd"])
                                       .output())
                                  .stdout)))
}
<commit_msg>Auto merge of #1134 - tommyip:master, r=Diggsey<commit_after>use std::env;
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;

struct Ignore;

impl<E> From<E> for Ignore
    where E: Error
{
    fn from(_: E) -> Ignore {
        Ignore
    }
}

fn main() {
    let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    File::create(out_dir.join("commit-info.txt"))
        .unwrap()
        .write_all(commit_info().as_bytes())
        .unwrap();
}

// Try to get hash and date of the last commit on a best effort basis. If anything goes wrong
// (git not installed or if this is not a git repository) just return an empty string.
fn commit_info() -> String {
    match (commit_hash(), commit_date()) {
        (Ok(hash), Ok(date)) => format!(" ({} {})", hash.trim_right(), date),
        _ => String::new(),
    }
}

fn commit_hash() -> Result<String, Ignore> {
    Ok(try!(String::from_utf8(try!(Command::new("git")
                                       .args(&["rev-parse", "--short=9", "HEAD"])
                                       .output())
                                  .stdout)))
}

fn commit_date() -> Result<String, Ignore> {
    Ok(try!(String::from_utf8(try!(Command::new("git")
                                       .args(&["log",
                                               "-1",
                                               "--date=short",
                                               "--pretty=format:%cd"])
                                       .output())
                                  .stdout)))
}
<|endoftext|>


<commit_before>#![feature(old_io, old_path)]
use std::old_io::Command;
use std::old_io::fs::PathExtensions;
use std::old_io::fs;
use std::env;

fn main() {
  let out_dir = env::var("OUT_DIR").unwrap();
  let mut objects = Vec::new();

  let files = fs::readdir(&Path::new("src")).unwrap();
  let mut files = files.iter().filter(|p| p.is_file());

  for file in files {
    if let Some(filename) = file.filename_str() {
      let filepath = format!("src/{}", filename);
      let outpath;

      if let Some(basename) = eat_extension(filename, ".c") {
        outpath = format!("{}/{}.o", out_dir, basename);

        Command::new("cc").args(&[&*filepath, "-c", "-fPIC", "-o"])
                          .arg(outpath.clone())
                          .status().unwrap();
      }
      else { continue }

      objects.push(outpath);
    }
  }

  Command::new("ar").args(&["crus", "libcontext.a"])
                    .args(&*objects)
                    .cwd(&Path::new(&out_dir))
                    .status().unwrap();

  println!("cargo:rustc-flags=-L {} -l context:static", out_dir);
}

fn eat_extension<'a>(s: &'a str, ext: &str) -> Option<&'a str> {
  if s.ends_with(ext) {
    Some(&s[..s.len() - ext.len()])
  }
  else {
    None
  }
}
<commit_msg>that doesn't need to be mutable<commit_after>#![feature(old_io, old_path)]
use std::old_io::Command;
use std::old_io::fs::PathExtensions;
use std::old_io::fs;
use std::env;

fn main() {
  let out_dir = env::var("OUT_DIR").unwrap();
  let mut objects = Vec::new();

  let files = fs::readdir(&Path::new("src")).unwrap();
  let files = files.iter().filter(|p| p.is_file());

  for file in files {
    if let Some(filename) = file.filename_str() {
      let filepath = format!("src/{}", filename);
      let outpath;

      if let Some(basename) = eat_extension(filename, ".c") {
        outpath = format!("{}/{}.o", out_dir, basename);

        Command::new("cc").args(&[&*filepath, "-c", "-fPIC", "-o"])
                          .arg(outpath.clone())
                          .status().unwrap();
      }
      else { continue }

      objects.push(outpath);
    }
  }

  Command::new("ar").args(&["crus", "libcontext.a"])
                    .args(&*objects)
                    .cwd(&Path::new(&out_dir))
                    .status().unwrap();

  println!("cargo:rustc-flags=-L {} -l context:static", out_dir);
}

fn eat_extension<'a>(s: &'a str, ext: &str) -> Option<&'a str> {
  if s.ends_with(ext) {
    Some(&s[..s.len() - ext.len()])
  }
  else {
    None
  }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::process::Command;

#[cfg(target_os="windows")]
fn build_lua() -> io::Result<()> {
    run_command_in_dir(&["make", "mingw"], Some(&build_dir().join("lua-5.3.0")))
}

/// The comand to build lua, specialized for different OSes.
#[cfg(target_os="macos")]
fn build_lua() -> io::Result<()> {
    run_command_in_dir(&["make", "macosx"], Some(&build_dir().join("lua-5.3.0")))
}

#[cfg(target_os="linux")]
fn build_lua() -> io::Result<()> {
    let dir = build_dir().join("lua-5.3.0");
    try!(run_command_in_dir(&["sed", "-i", "s/^MYCFLAGS=.*/MYCFLAGS=-fPIC/g", "src/Makefile"],
                            Some(&dir)));
    run_command_in_dir(&["make", "linux"], Some(&dir))
}

/// Runs the command 'all_args[0]' with the arguments 'all_args[1..]' in the
/// current directory.
fn run_command(all_args: &[&str]) -> io::Result<()> {
    run_command_in_dir(all_args, None)
}

/// Runs the command 'all_args[0]' with the arguments 'all_args[1..]' in the
/// directory 'cwd' or the current directory.
fn run_command_in_dir(all_args: &[&str], cwd: Option<&Path>) -> io::Result<()> {
    let command_name = all_args[0];
    let args = &all_args[1..];
    let mut command = Command::new(command_name);
    command.args(args);
    if let Some(cwd) = cwd {
        command.current_dir(cwd);
    }
    let status = try!(command.status());
    if !status.success() {
        return Err(io::Error::new(io::ErrorKind::Other, format!("The command\n\
        \t{}\n\
        did not run successfully.", all_args.connect(" "))));
    }
    Ok(())
}

/// The cargo output directory for builds from this.
fn build_dir() -> PathBuf {
    PathBuf::from(env::var("OUT_DIR").unwrap())
}

/// If a static Lua is not yet available from a prior run of this script, this
/// will download Lua and build it. The cargo configuration text to link
/// statically against lua.a is then printed to stdout.
fn prebuild() ->io::Result<()> {
    if !fs::metadata(
        &build_dir().join("lua-5.3.0").join("src").join("liblua.a")
    ).is_ok() {
        try!(fs::create_dir_all(&build_dir()));

        // Compile Lua.
        try!(run_command_in_dir(&["wget",
                                "http://www.lua.org/ftp/lua-5.3.0.tar.gz"],
                                Some(&build_dir())));
        try!(run_command_in_dir(&["tar", "xzvf", "lua-5.3.0.tar.gz"],
                                Some(&build_dir())));

        try!(build_lua());

        // Compile and run glue.c.
        let glue = build_dir().join("glue").to_string_lossy().into_owned();
        try!(run_command(&["gcc",
                         "-I", &build_dir().join("lua-5.3.0").join("src").to_string_lossy(),
                         &PathBuf::from("src").join("glue").join("glue.c").to_string_lossy(),
                         "-o", &glue]));
        try!(run_command(&[&glue, "src/ffi/glue.rs"]));
    }

    let mut build_dir_absolute = try!(env::current_dir());
    build_dir_absolute.push(&build_dir());
    build_dir_absolute.push("lua-5.3.0");
    build_dir_absolute.push("src");

    println!("cargo:rustc-link-lib=static=lua");
    println!("cargo:rustc-link-search=native={}", build_dir_absolute.to_string_lossy());

    Ok(())
}

fn main() {
    match prebuild() {
        Err(e) => panic!("Error: {}", e),
        Ok(()) => (),
    }
}
<commit_msg>Fix build for FreeBSD and DragonFly<commit_after>use std::env;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::process::Command;

#[cfg(target_os="windows")]
fn build_lua() -> io::Result<()> {
    run_command_in_dir(&["make", "mingw"], Some(&build_dir().join("lua-5.3.0")))
}

/// The comand to build lua, specialized for different OSes.
#[cfg(target_os="macos")]
fn build_lua() -> io::Result<()> {
    run_command_in_dir(&["make", "macosx"], Some(&build_dir().join("lua-5.3.0")))
}

#[cfg(target_os="linux")]
fn build_lua() -> io::Result<()> {
    let dir = build_dir().join("lua-5.3.0");
    try!(run_command_in_dir(&["sed", "-i", "s/^MYCFLAGS=.*/MYCFLAGS=-fPIC/g", "src/Makefile"],
                            Some(&dir)));
    run_command_in_dir(&["make", "linux"], Some(&dir))
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
fn build_lua() -> io::Result<()> {
    let dir = build_dir().join("lua-5.3.0");
    try!(run_command_in_dir(&["sed", "-e", "s/^MYCFLAGS=.*/MYCFLAGS=-fPIC/g", "-i", "bak", "src/Makefile"],
                            Some(&dir)));
    if cfg!(target_os = "freebsd") {
        run_command_in_dir(&["make", "freebsd"], Some(&dir))
    } else {
        run_command_in_dir(&["make", "bsd"], Some(&dir))
    }
}

/// Runs the command 'all_args[0]' with the arguments 'all_args[1..]' in the
/// current directory.
fn run_command(all_args: &[&str]) -> io::Result<()> {
    run_command_in_dir(all_args, None)
}

/// Runs the command 'all_args[0]' with the arguments 'all_args[1..]' in the
/// directory 'cwd' or the current directory.
fn run_command_in_dir(all_args: &[&str], cwd: Option<&Path>) -> io::Result<()> {
    let command_name = all_args[0];
    let args = &all_args[1..];
    let mut command = Command::new(command_name);
    command.args(args);
    if let Some(cwd) = cwd {
        command.current_dir(cwd);
    }
    let status = try!(command.status());
    if !status.success() {
        return Err(io::Error::new(io::ErrorKind::Other, format!("The command\n\
        \t{}\n\
        did not run successfully.", all_args.connect(" "))));
    }
    Ok(())
}

/// The cargo output directory for builds from this.
fn build_dir() -> PathBuf {
    PathBuf::from(env::var("OUT_DIR").unwrap())
}

#[cfg(not(any(target_os = "freebsd", target_os = "dragonfly")))]
const FETCH_CMD: &'static str = "wget";
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
const FETCH_CMD: &'static str = "fetch";

/// If a static Lua is not yet available from a prior run of this script, this
/// will download Lua and build it. The cargo configuration text to link
/// statically against lua.a is then printed to stdout.
fn prebuild() ->io::Result<()> {
    if !fs::metadata(
        &build_dir().join("lua-5.3.0").join("src").join("liblua.a")
    ).is_ok() {
        try!(fs::create_dir_all(&build_dir()));

        // Compile Lua.
        try!(run_command_in_dir(&[FETCH_CMD,
                                "http://www.lua.org/ftp/lua-5.3.0.tar.gz"],
                                Some(&build_dir())));
        try!(run_command_in_dir(&["tar", "xzvf", "lua-5.3.0.tar.gz"],
                                Some(&build_dir())));

        try!(build_lua());

        // Compile and run glue.c.
        let glue = build_dir().join("glue").to_string_lossy().into_owned();
        try!(run_command(&["gcc",
                         "-I", &build_dir().join("lua-5.3.0").join("src").to_string_lossy(),
                         &PathBuf::from("src").join("glue").join("glue.c").to_string_lossy(),
                         "-o", &glue]));
        try!(run_command(&[&glue, "src/ffi/glue.rs"]));
    }

    let mut build_dir_absolute = try!(env::current_dir());
    build_dir_absolute.push(&build_dir());
    build_dir_absolute.push("lua-5.3.0");
    build_dir_absolute.push("src");

    println!("cargo:rustc-link-lib=static=lua");
    println!("cargo:rustc-link-search=native={}", build_dir_absolute.to_string_lossy());

    Ok(())
}

fn main() {
    match prebuild() {
        Err(e) => panic!("Error: {}", e),
        Ok(()) => (),
    }
}
<|endoftext|>


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

use std::env;

use std::path::Path;

use cc::Build;

fn main() {
    let platform = if cfg!(target_os = "linux") {
        "linux"
    } else if cfg!(target_os = "windows") {
        "windows"
    } else {
        panic!("Unsupported OS")
    };

    Build::new()
        .include("src")
        .include("src/net/raw/devices")
        .file("src/net/raw/devices/devices-common.c")
        .file(&format!("src/net/raw/devices/devices-{}.c", platform))
        .compile("net_devices");

    if cfg!(feature = "discovery") {
        let mut wrapper_builder = Build::new();

        if cfg!(target_os = "windows") {
            // on Windows, we primarily try to find the lib using vcpkg
            let lib = vcpkg::Config::new()
                .cargo_metadata(true)
                .emit_includes(false)
                .copy_dlls(false)
                .find_package("winpcap");

            if let Ok(lib) = lib {
                for include in lib.include_paths {
                    wrapper_builder.include(include);
                }
            } else {
                // if vcpkg cannot find the lib, we try the env. variables
                if let Some(dir) = dir_from_var("WINPCAP_LIB_DIR") {
                    emit_lib_path(&dir);
                }

                if let Some(dir) = dir_from_var("WINPCAP_INCLUDE_DIR") {
                    wrapper_builder.include(dir);
                }

                link("winpcap", "WINPCAP_STATIC");
            }
        } else {
            // on other platforms, we expect the lib will be in standard paths or the paths will be
            // defined using env. variables
            if let Some(dir) = dir_from_var("LIBPCAP_LIB_DIR") {
                emit_lib_path(&dir);
            }

            if let Some(dir) = dir_from_var("LIBPCAP_INCLUDE_DIR") {
                wrapper_builder.include(dir);
            }

            link("pcap", "LIBPCAP_STATIC");
        }

        wrapper_builder
            .include("src")
            .include("src/net/raw/pcap")
            .file("src/net/raw/pcap/wrapper-common.c")
            .file(&format!("src/net/raw/pcap/wrapper-{}.c", platform))
            .compile("pcap_wrapper");
    }
}

fn is_dir(d: &str) -> bool {
    let path = Path::new(d);

    path.is_dir()
}

fn link(lib: &str, static_flag_var: &str) {
    println!("cargo:rustc-link-lib={}={}", lib_mode(static_flag_var), lib);
}

fn emit_lib_path(path: &str) {
    println!("cargo:rustc-link-search=native={}", path);
}

fn lib_mode(static_flag_var: &str) -> &'static str {
    let kind = env::var(static_flag_var);

    match kind.ok().as_ref().map(|v| v.as_str()) {
        Some("0") => "dylib",
        Some(_) => "static",
        None => "dylib",
    }
}

fn dir_from_var(var: &str) -> Option<String> {
    if let Ok(dir) = env::var(var) {
        if is_dir(&dir) {
            return Some(dir);
        }
    }

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

use std::env;

use std::ffi::{OsStr, OsString};
use std::path::Path;

use cc::Build;

fn main() {
    build_net_devices();

    if cfg!(feature = "discovery") {
        // Note: We need to build the wrapper first and then link WinPcap/libpcap. Otherwise, they
        // would link in an incorrect order and the dynamic library would be missing a dependency.
        build_pcap_wrapper();
        link_pcap();
    }
}

fn is_dir(d: &OsStr) -> bool {
    let path = Path::new(d);

    path.is_dir()
}

fn link(lib: &str, static_flag_var: &str) {
    let link_static_lib = flag_from_var(static_flag_var);

    if link_static_lib.unwrap_or(false) {
        println!("cargo:rustc-link-lib=static={}", lib);
    } else {
        println!("cargo:rustc-link-lib={}", lib);
    }
}

fn emit_lib_path(path: &OsStr) {
    let path = path.to_str().expect("lib path is not UTF-8 encoded");

    println!("cargo:rustc-link-search=native={}", path);
}

fn flag_from_var(flag_var: &str) -> Option<bool> {
    env::var_os(flag_var).map(|v| &v.to_string_lossy() != "0")
}

fn dir_from_var(var: &str) -> Option<OsString> {
    if let Some(dir) = env::var_os(var) {
        if is_dir(&dir) {
            return Some(dir);
        }
    }

    None
}

fn get_platform() -> &'static str {
    if cfg!(target_os = "linux") {
        "linux"
    } else if cfg!(target_os = "windows") {
        "windows"
    } else {
        panic!("Unsupported OS")
    }
}

fn build_net_devices() {
    Build::new()
        .include("src")
        .include("src/net/raw/devices")
        .file("src/net/raw/devices/devices-common.c")
        .file(&format!("src/net/raw/devices/devices-{}.c", get_platform()))
        .compile("net_devices");
}

fn build_pcap_wrapper() {
    let mut wrapper_builder = Build::new();

    if cfg!(target_os = "windows") {
        // on Windows, we primarily try to find the lib using vcpkg
        let lib = vcpkg::Config::new()
            .cargo_metadata(false)
            .emit_includes(false)
            .copy_dlls(false)
            .find_package("winpcap");

        if let Ok(lib) = lib {
            for include in lib.include_paths {
                wrapper_builder.include(include);
            }
        } else if let Some(dir) = dir_from_var("WINPCAP_INCLUDE_DIR") {
            // if vcpkg cannot find the lib, we try the env. variable
            wrapper_builder.include(dir);
        }
    } else if let Some(dir) = dir_from_var("LIBPCAP_INCLUDE_DIR") {
        // on other platforms, we expect the lib will be in standard paths or the paths will be
        // defined using env. variables
        wrapper_builder.include(dir);
    }

    wrapper_builder
        .include("src")
        .include("src/net/raw/pcap")
        .file("src/net/raw/pcap/wrapper-common.c")
        .file(&format!("src/net/raw/pcap/wrapper-{}.c", get_platform()))
        .compile("pcap_wrapper");
}

fn link_pcap() {
    if cfg!(target_os = "windows") {
        // on Windows, we primarily try to find the lib using vcpkg
        let lib = vcpkg::Config::new()
            .cargo_metadata(true)
            .emit_includes(false)
            .copy_dlls(false)
            .find_package("winpcap");

        // if vcpkg cannot find the lib, we try the env. variables
        if lib.is_err() {
            if let Some(dir) = dir_from_var("WINPCAP_LIB_DIR") {
                emit_lib_path(&dir);
            }

            link("winpcap", "WINPCAP_STATIC");
        }
    } else {
        // on other platforms, we expect the lib will be in standard paths or the paths will be
        // defined using env. variables
        if let Some(dir) = dir_from_var("LIBPCAP_LIB_DIR") {
            emit_lib_path(&dir);
        }

        link("pcap", "LIBPCAP_STATIC");
    }
}
<|endoftext|>


<commit_before>//! View bits in memory with turtles
//!
//! This example uses [@myrrlyn]’s [`bitvec`] crate to turn data into strings of
//! bits, and then draws them on the screen.
//!
//! You are encouraged to change both the data used to seed the turtle, and the
//! `bitvec` calls that control how the turtle acts, to see what changes.
//!
//! [@myrrlyn]: //github.com/myrrlyn
//! [`bitvec`]: //crates.io/crates/bitvec

// The `bitvec` crate provides a bunch of types for us to use with one import
use bitvec::prelude::*;
use turtle::Turtle;

/// Set the line length for each displayed bit
const BIT_WIDTH: f64 = 20.0;
/// Set the vertical spacing between successive rows of bits
const BIT_HEIGHT: f64 = 10.0;
/// Set the horizontal spacing between successive bits in a row
const BIT_MARGIN: f64 = BIT_WIDTH / 2.0;
/// Compute the total width of a bit plus its spacing
const BIT_BOX: f64 = BIT_WIDTH + BIT_MARGIN;

fn main() {
    // Replace this text with a message of your own to see how it changes on the
    // screen.
    //
    // Try translating the displayed lines to binary numbers and work out their
    // encoding!
    let text = "¡Hola, mundo! 🌍🌏🌎";

    // This block sets up the turtle to draw bits more or less centered in the
    // screen. The turtle works by walking horizontally for each bit in a byte,
    // then backtracking and walking vertically to the next byte.
    let mut turtle = Turtle::new();
    turtle.pen_up();
    // Compute the boundaries of the part of the screen where the turtle will
    // draw
    let right_edge = BIT_BOX * 4.0;
    let top_edge = BIT_HEIGHT * (text.len() as f64 / 2.0);
    // The turtle starts from the top right of the region,
    turtle.go_to((right_edge, top_edge));
    // and walks left
    turtle.set_heading(180.0);

    // Now let’s draw some data on the screen, as individual bits

    // Rust strings can iterate over the bytes used to represent them.
    for byte in text.bytes() {
        // For each byte (`u8`), we use `bitvec` to make a view into its bits.
        //
        // The `LittleEndian` means that the view moves from right to left
        // across the byte, which fits how our turtle moves from right to left
        // across the screen.
        let bits = byte.bits::<LittleEndian>();
        // Then we draw the byte’s bits as a row
        draw_row(&mut turtle, bits);
        // And reset the turtle to the right edge.
        turtle.set_x(right_edge);
    }

    // `bitvec` can look at more than just `u8`. Let’s try looking at the bits
    // that represent a number!

    // First we need to pick a number. Rust provides some interesting numbers
    // for us.
    let tau = std::f64::consts::PI * 2.0;
    // But `bitvec` doesn’t know how to view all numbers. The standard library
    // provides a function `to_bits(f64) -> u64`, which turns it into a number
    // `bitvec` does know how to view.
    let raw_number = tau.to_bits();
    // `bitvec` can also view bits from left to right, with `BigEndian`.
    let bits = raw_number.bits::<BigEndian>();

    // Since we are reading bits from left to right, the turtle should move from
    // left to right also. Change the `* 2.0` to move the section horizontally.
    let left_edge = -right_edge * 2.0;
    turtle.set_x(left_edge);
    // Walk from left to right
    turtle.set_heading(0.0);

    // The `&BitSlice` type acts just like `&[bool]`, so it comes with a
    // `.chunks` method which divides it into smaller pieces. `bitvec` can take
    // any number, not just multiples of 8, but 16 is a convenient number to
    // look at. Try changing it to a different number, like 10, to see what
    // happens!
    for row in bits.chunks(16) {
        // Each chunk produced is a smaller `&BitSlice`, just like
        // `&[bool].chunks` produces smaller `&[bool]`s, so we can draw it.
        draw_row(&mut turtle, row);
        // After each row, the turtle has to go back to the left edge.
        turtle.set_x(left_edge);
    }
}

/// Draw a row of bits on the screen.
///
/// This takes a reference to a turtle, which draws, and a reference to a slice
/// of bits, which provides the data to draw.
fn draw_row<C, T>(t: &mut Turtle, row: &BitSlice<C, T>)
where C: Cursor, T: BitStore {
    // `&BitSlice` can iterate over bits. It is just like `&[bool]`, and so it
    // produces `&bool` for each loop.
    for bit in row {
        // This checks if the bit produced by the row is `1` or `0`, and sets
        // the pen color to black (`1`) or light grey (`0`)
        if *bit {
            t.set_pen_color("black");
        }
        else {
            t.set_pen_color("light grey");
        }

        // For each bit, the loop puts down the pen to draw a line of the bit’s
        // color, then picks up the pen to add some horizontal spacing between
        // them.
        t.pen_down();
        t.forward(BIT_WIDTH);
        t.pen_up();
        t.forward(BIT_MARGIN);
    }

    // After the row is complete, the turtle picks up its pen,
    t.pen_up();
    // rememebers which direction it was going,
    let old_heading = t.heading();
    // turns to face down the screen,
    t.set_heading(270.0);
    // moves down by a row,
    t.forward(BIT_HEIGHT);
    // then goes back to its old direction.
    t.set_heading(old_heading);
    // This way each row gets vertical spacing between them.
}
<commit_msg>Address review<commit_after>//! View bits in memory with turtles
//!
//! This example uses [@myrrlyn]'s [`bitvec`] crate to turn data into strings of
//! bits, and then draws them on the screen.
//!
//! You are encouraged to change both the data used to seed the turtle, and the
//! `bitvec` calls that control how the turtle acts, to see what changes.
//!
//! [@myrrlyn]: //github.com/myrrlyn
//! [`bitvec`]: //crates.io/crates/bitvec

// The `bitvec` crate provides a lot of types; we only need a few:
use bitvec::prelude::*;
    // This trait provides the `.bits::<_>()` method which we use on Rust types
    // to make `bitvec` views,
use turtle::Turtle;

/// Set the line length for each displayed bit
const BIT_WIDTH: f64 = 20.0;
/// Set the vertical spacing between successive rows of bits
const BIT_HEIGHT: f64 = 10.0;
/// Set the horizontal spacing between successive bits in a row
const BIT_MARGIN: f64 = BIT_WIDTH / 2.0;
/// Compute the total width of a bit plus its spacing
const BIT_BOX: f64 = BIT_WIDTH + BIT_MARGIN;

fn main() {
    // This block sets up the turtle to draw bits more or less centered in the
    // screen. The turtle works by walking horizontally for each bit in a byte,
    // then backtracking and walking vertically to the next byte.
    let mut turtle = Turtle::new();
    turtle.pen_up();
    // Compute the boundaries of the part of the screen where the turtle will
    // draw
    let right_edge = BIT_BOX * 4.0;

    // Now let's draw some data on the screen, as individual bits

    // Replace this text with a message of your own to see how it changes on the
    // screen.
    //
    // Try translating the displayed lines to binary numbers and work out their
    // encoding!
    let text = "¡Hola, mundo! 🌍🌏🌎";

    // Place the turtle according to the length of the text span
    let top_edge = BIT_HEIGHT * (text.len() as f64 / 2.0);
    // The turtle starts from the top right of the region,
    turtle.go_to((right_edge, top_edge));
    // and walks left
    turtle.set_heading(180.0);

    // Rust strings can iterate over their individual characters. This block
    // loops over characters, collecting their start point in the text so that
    // we can grab the encoded bytes of each one.
    let mut row_num = 0;
    for (char_num, (start, codepoint)) in text.char_indices().enumerate() {
        println!("Character {}: {}", char_num, codepoint);
        // Each character has a variable width, so we need to find that.
        let byte_count = codepoint.len_utf8();
        // And then collect the bytes of the string that make up the character.
        let row = &text.as_bytes()[start ..][.. byte_count];

        // For each byte (`u8`), we use `bitvec` to make a view into its bits.
        // `bitvec` provides the `.bits::<_>()` method on Rust integers for easy
        // access to its view types.
        //
        // The `LittleEndian` means that the view moves from least significant
        // bit to most significant. Since we want to display on screen the most
        // significant bit on the left, and the least on the right, the turtle
        // will have to move from right to left to match.
        //
        // These types describe different ways to view the same data. You can
        // read more about them in the `bitvec` docs, and at Wikipedia:
        // https://docs.rs/bitvec/0.16.1/bitvec/cursor/index.html
        // https://en.wikipedia.org/wiki/Endianness#Bit_endianness
        for byte in row {
            println!("  Byte {:02}:\n    Value: 0x{:02X}\n    Bits: {:08b}", row_num, byte, byte);

            let bits = byte.bits::<LittleEndian>();

            // Then we draw the byte's bits as a row
            draw_row(&mut turtle, bits);
            // And reset the turtle to the right edge.
            turtle.set_x(right_edge);

            row_num += 1;
        }
    }

    // `bitvec` can look at more than just `u8`. Let's try looking at the bits
    // that represent a number!

    // First we need to pick a number. Rust provides some interesting numbers
    // for us.
    let num = std::f64::consts::PI * 2.0;

    // But `bitvec` doesn't know how to view all numbers. The standard library
    // provides a function `to_bits(f64) -> u64`, which turns it into a number
    // `bitvec` does know how to view.
    //
    // The `f64` data type has a memory encoding standardized by the IEEE-754
    // document. You can read more about it here:
    // https://en.wikipedia.org/wiki/Double-precision_floating-point_format
    let raw_number = num.to_bits();

    // `bitvec` can also view bits from left to right, with `BigEndian`.
    let bits = raw_number.bits::<BigEndian>();

    // Since we are reading bits from left to right, the turtle should move from
    // left to right also. Change the `* 2.0` to move the section horizontally.
    let left_edge = -right_edge * 2.0;
    turtle.set_x(left_edge);
    // Walk from left to right
    turtle.set_heading(0.0);

    // The `&BitSlice` type acts just like `&[bool]`, so it comes with a
    // `.chunks` method which divides it into smaller pieces. `bitvec` can take
    // any number, not just multiples of 8, but 16 is a convenient number to
    // look at. Try changing it to a different number, like 10, to see what
    // happens!
    for (num, row) in bits.chunks(16).enumerate() {
        println!("Row {} bits: {:b}", num, row);
        // Each chunk produced is a smaller `&BitSlice`, just like
        // `&[bool].chunks` produces smaller `&[bool]`s, so we can draw it.
        draw_row(&mut turtle, row);
        // After each row, the turtle has to go back to the left edge.
        turtle.set_x(left_edge);
    }
}

/// Draw a row of bits on the screen.
///
/// This takes a reference to a turtle, which draws, and a reference to a slice
/// of bits, which provides the data to draw.
fn draw_row<C, T>(t: &mut Turtle, row: &BitSlice<C, T>)
where C: Cursor, T: BitStore {
    // `&BitSlice` can iterate over bits. It is just like `&[bool]`, and so it
    // produces `&bool` for each loop.
    for &bit in row {
        // This checks if the bit produced by the row is `1` or `0`, and sets
        // the pen color to black (`1`) or light grey (`0`)
        if bit {
            t.set_pen_color("black");
        }
        else {
            t.set_pen_color("light grey");
        }

        // For each bit, the loop puts down the pen to draw a line of the bit's
        // color, then picks up the pen to add some horizontal spacing between
        // them.
        t.pen_down();
        t.forward(BIT_WIDTH);
        t.pen_up();
        t.forward(BIT_MARGIN);
    }

    // After the row is complete, the turtle picks up its pen,
    t.pen_up();
    // rememebers which direction it was going,
    let old_heading = t.heading();
    // turns to face down the screen,
    t.set_heading(270.0);
    // moves down by a row,
    t.forward(BIT_HEIGHT);
    // then goes back to its old direction.
    t.set_heading(old_heading);
    // This way each row gets vertical spacing between them.
}
<|endoftext|>