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

/// 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 = self.up_axis.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.yaw.sin() * self.pitch.sin();
        let pz = self.at.z + self.dist * self.pitch.cos();

        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 license of arc_ball.rs<commit_after>/*
Based on https://github.com/sebcrozet/kiss3d/blob/master/src/camera/arc_ball.rs
(Because I don't know how to fix set_up_axis, I modified to use Z-up always.)

Copyright (c) 2013, Sébastien Crozet
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the author nor the names of its contributors may be used
   to endorse or promote products derived from this software without specific
   prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
use kiss3d::camera::Camera;
use kiss3d::event::{Action, Key, MouseButton, WindowEvent};
use kiss3d::resource::ShaderUniform;
use kiss3d::window::Canvas;
use na::{self, Isometry3, Matrix4, Perspective3, Point3, Vector2, Vector3};
use std::f32;

/// 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 = self.up_axis.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.yaw.sin() * self.pitch.sin();
        let pz = self.at.z + self.dist * self.pitch.cos();

        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>#[allow(non_snake_case)]
#[allow(dead_code)]
pub mod registers;
#[allow(non_snake_case)]
#[allow(dead_code)]
#[allow(unused_variables)] // to remove when memory implemented
pub mod memory;
#[allow(non_snake_case)]
#[allow(dead_code)]
pub mod cpu;
#[allow(non_snake_case)]
#[allow(dead_code)]
pub mod instrs;
#[allow(non_snake_case)]
#[allow(dead_code)]
pub mod rom_structs;
mod arch_tests;
<commit_msg>fixed tests<commit_after>#[allow(non_snake_case)]
#[allow(dead_code)]
pub mod registers;
#[allow(non_snake_case)]
#[allow(dead_code)]
#[allow(unused_variables)] // to remove when memory implemented
pub mod memory;
#[allow(non_snake_case)]
#[allow(dead_code)]
pub mod cpu;
#[allow(non_snake_case)]
#[allow(dead_code)]
#[macro_use]
pub mod instrs;
#[allow(non_snake_case)]
#[allow(dead_code)]
pub mod rom_structs;
mod arch_tests;
<|endoftext|>


<commit_before>use clap::{Arg, ArgMatches, App};
use slog::Level;

use rt::Dim;

pub struct Config {
    pub output_file: String,
    pub log_level: Level,
    pub dim: Dim,
    pub integrator: SamplerIntegratorType,
    pub threads: u32,
}

arg_enum! {
  #[derive(Debug)]
  pub enum SamplerIntegratorType {
      Whitted,
      DirectLighting,
      PathTracing,
      Ao,
      Normal
  }
}

pub fn parse_args<'a>() -> ArgMatches<'a> {
    // TODO add block-size and ao-samples and whitted-max-ray? Or maybe not since eventually it
    // will be read from the scene file...
    App::new("rustracer")
        .version("0.1")
        .author("Antoine Büsch")
        .about("Toy raytracer in Rust based on PBRTv3")
        .arg(Arg::with_name("output")
                 .long("output")
                 .short("o")
                 .help("Output file name")
                 .default_value("image.png"))
        .arg(Arg::with_name("threads")
                 .long("threads")
                 .short("t")
                 .help("Number of worker threads")
                 .takes_value(true))
        .arg(Arg::with_name("dim")
                 .long("dim")
                 .short("d")
                 .help("Dimension of the output image")
                 .default_value("800x600"))
        .arg(Arg::with_name("integrator")
                 .long("integrator")
                 .short("i")
                 .help("SamplerIntegrator to use")
                 .possible_values(&SamplerIntegratorType::variants())
                 .default_value("DirectLighting"))
        .arg(Arg::with_name("spp").long("spp").help("Sample per pixels").default_value("4"))
        .arg(Arg::with_name("verbose").short("v").help("log debug information"))
        .arg(Arg::with_name("display").short("p").help("Display image as it is rendered"))
        .get_matches()
}
<commit_msg>Remove unused struct<commit_after>use clap::{Arg, ArgMatches, App};

arg_enum! {
  #[derive(Debug)]
  pub enum SamplerIntegratorType {
      Whitted,
      DirectLighting,
      PathTracing,
      Ao,
      Normal
  }
}

pub fn parse_args<'a>() -> ArgMatches<'a> {
    // TODO add block-size and ao-samples and whitted-max-ray? Or maybe not since eventually it
    // will be read from the scene file...
    App::new("rustracer")
        .version("0.1")
        .author("Antoine Büsch")
        .about("Toy raytracer in Rust based on PBRTv3")
        .arg(Arg::with_name("output")
                 .long("output")
                 .short("o")
                 .help("Output file name")
                 .default_value("image.png"))
        .arg(Arg::with_name("threads")
                 .long("threads")
                 .short("t")
                 .help("Number of worker threads")
                 .takes_value(true))
        .arg(Arg::with_name("dim")
                 .long("dim")
                 .short("d")
                 .help("Dimension of the output image")
                 .default_value("800x600"))
        .arg(Arg::with_name("integrator")
                 .long("integrator")
                 .short("i")
                 .help("SamplerIntegrator to use")
                 .possible_values(&SamplerIntegratorType::variants())
                 .default_value("DirectLighting"))
        .arg(Arg::with_name("spp").long("spp").help("Sample per pixels").default_value("4"))
        .arg(Arg::with_name("verbose").short("v").help("log debug information"))
        .arg(Arg::with_name("display").short("p").help("Display image as it is rendered"))
        .get_matches()
}
<|endoftext|>


<commit_before>use std::io::{Error, ErrorKind, Read, Result};

use futures::{Async, AsyncSink, Future, Sink, Stream};
use tokio_core::reactor::Handle;
use futures::sync::mpsc::{channel, Receiver, Sender};

pub struct AsyncRead {
    _pool: ::futures_cpupool::CpuPool,
    size_sender: Sender<usize>,
    result_receiver: Receiver<Result<Vec<u8>>>,
    debt: Vec<u8>,
}

pub fn async_read<R>(handle: &Handle, mut read: R) -> AsyncRead
where
    R: Read + Send + 'static,
{
    let (size_sender, size_receiver) = channel(1);
    let (result_sender, result_receiver) = channel(1);

    let future = Noisy(size_receiver, "size")
        .map_err(|_| {
            panic!("Size sender shut down");
        })
        .map(move |size| {
            let mut buffer = vec![0; size];
            match read.read(&mut buffer) {
                Ok(len) => {
                    buffer.truncate(len);
                    Ok(buffer)
                }
                Err(err) => Err(err),
            }
        })
        .forward(Noisy(result_sender, "result").sink_map_err(|_| {
            panic!("Result receiver shut down");
        }))
        .map(|_| ());

    let pool = ::futures_cpupool::Builder::new()
        .pool_size(1)
        .name_prefix("input-reader-")
        .create();
    handle.spawn(pool.spawn(future));
    AsyncRead {
        _pool: pool,
        size_sender,
        result_receiver,
        debt: Vec::new(),
    }
}

impl AsyncRead {
    fn handle_input(&mut self, buf: &mut [u8], result: Result<Vec<u8>>) -> Result<usize> {
        let buffer = result?;
        let copy_len = buffer.len().min(buf.len());
        buf[..copy_len].copy_from_slice(&buffer[..copy_len]);
        self.debt.extend_from_slice(&buffer[copy_len..]);
        Ok(copy_len)
    }
}

impl Read for AsyncRead {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        if !self.debt.is_empty() {
            let copy_len = self.debt.len().min(buf.len());
            buf[..copy_len].copy_from_slice(&self.debt[..copy_len]);
            self.debt.drain(..copy_len);
            return Ok(copy_len);
        }
        match self.result_receiver.poll() {
            Ok(Async::Ready(Some(result))) => self.handle_input(buf, result),
            Ok(Async::Ready(None)) => Ok(0),

            Ok(Async::NotReady) => match self.size_sender.start_send(buf.len()) {
                Ok(AsyncSink::Ready) => match self.result_receiver.poll() {
                    Ok(Async::Ready(Some(result))) => self.handle_input(buf, result),
                    Ok(Async::Ready(None)) => Ok(0),
                    Ok(Async::NotReady) => Err(Error::new(
                        ErrorKind::WouldBlock,
                        "Waiting on input to be available",
                    )),
                    Err(_) => Err(ErrorKind::BrokenPipe.into()),
                },

                Ok(AsyncSink::NotReady(_)) => Err(Error::new(
                    ErrorKind::WouldBlock,
                    "Waiting on input to be available",
                )),
                Err(_) => match self.result_receiver.poll() {
                    Ok(Async::Ready(Some(result))) => self.handle_input(buf, result),
                    Ok(Async::Ready(None)) => Ok(0),
                    Ok(Async::NotReady) => Err(Error::new(
                        ErrorKind::WouldBlock,
                        "Waiting on input to be available",
                    )),
                    Err(_) => Err(Error::new(ErrorKind::Other, "Read thread has stopped")),
                },
            },

            Err(_) => Err(ErrorKind::BrokenPipe.into()),
        }
    }
}

impl ::tokio_io::AsyncRead for AsyncRead {}

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

    use partial_io::{GenInterrupted, PartialAsyncRead, PartialOp, PartialWithErrors};
    use tokio_io::io::read_to_end;

    quickcheck! {
        fn partial_io(seq: PartialWithErrors<GenInterrupted>, input: Vec<u8>) -> bool {
            let mut core = ::tokio_core::reactor::Core::new().unwrap();

            let reader = async_read(&core.handle(), ::std::io::Cursor::new(input.clone()));
            let partial_reader = PartialAsyncRead::new(reader, seq);

            core.run(read_to_end(partial_reader, vec![])).ok().map(|t| t.1) == Some(input)
        }
    }

    #[test]
    fn partial_2_1() {
        let mut core = ::tokio_core::reactor::Core::new().unwrap();

        let input = vec![0, 0];
        let reader = async_read(&core.handle(), ::std::io::Cursor::new(input.clone()));
        let seq = vec![PartialOp::Limited(2), PartialOp::Limited(1)];
        let partial_reader = PartialAsyncRead::new(reader, seq);

        assert_eq!(
            core.run(read_to_end(partial_reader, vec![]))
                .ok()
                .map(|t| t.1),
            Some(input)
        );
    }
}
<commit_msg>Fix async_io compilation<commit_after>use std::io::{Error, ErrorKind, Read, Result};

use futures::{Async, AsyncSink, Future, Sink, Stream};
use tokio_core::reactor::Handle;
use futures::sync::mpsc::{channel, Receiver, Sender};

pub struct AsyncRead {
    _pool: ::futures_cpupool::CpuPool,
    size_sender: Sender<usize>,
    result_receiver: Receiver<Result<Vec<u8>>>,
    debt: Vec<u8>,
}

pub fn async_read<R>(handle: &Handle, mut read: R) -> AsyncRead
where
    R: Read + Send + 'static,
{
    let (size_sender, size_receiver) = channel(1);
    let (result_sender, result_receiver) = channel(1);

    let future = size_receiver
        .map_err(|_| {
            panic!("Size sender shut down");
        })
        .map(move |size| {
            let mut buffer = vec![0; size];
            match read.read(&mut buffer) {
                Ok(len) => {
                    buffer.truncate(len);
                    Ok(buffer)
                }
                Err(err) => Err(err),
            }
        })
        .forward(result_sender.sink_map_err(|_| {
            panic!("Result receiver shut down");
        }))
        .map(|_| ());

    let pool = ::futures_cpupool::Builder::new()
        .pool_size(1)
        .name_prefix("input-reader-")
        .create();
    handle.spawn(pool.spawn(future));
    AsyncRead {
        _pool: pool,
        size_sender,
        result_receiver,
        debt: Vec::new(),
    }
}

impl AsyncRead {
    fn handle_input(&mut self, buf: &mut [u8], result: Result<Vec<u8>>) -> Result<usize> {
        let buffer = result?;
        let copy_len = buffer.len().min(buf.len());
        buf[..copy_len].copy_from_slice(&buffer[..copy_len]);
        self.debt.extend_from_slice(&buffer[copy_len..]);
        Ok(copy_len)
    }
}

impl Read for AsyncRead {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        if !self.debt.is_empty() {
            let copy_len = self.debt.len().min(buf.len());
            buf[..copy_len].copy_from_slice(&self.debt[..copy_len]);
            self.debt.drain(..copy_len);
            return Ok(copy_len);
        }
        match self.result_receiver.poll() {
            Ok(Async::Ready(Some(result))) => self.handle_input(buf, result),
            Ok(Async::Ready(None)) => Ok(0),

            Ok(Async::NotReady) => match self.size_sender.start_send(buf.len()) {
                Ok(AsyncSink::Ready) => match self.result_receiver.poll() {
                    Ok(Async::Ready(Some(result))) => self.handle_input(buf, result),
                    Ok(Async::Ready(None)) => Ok(0),
                    Ok(Async::NotReady) => Err(Error::new(
                        ErrorKind::WouldBlock,
                        "Waiting on input to be available",
                    )),
                    Err(_) => Err(ErrorKind::BrokenPipe.into()),
                },

                Ok(AsyncSink::NotReady(_)) => Err(Error::new(
                    ErrorKind::WouldBlock,
                    "Waiting on input to be available",
                )),
                Err(_) => match self.result_receiver.poll() {
                    Ok(Async::Ready(Some(result))) => self.handle_input(buf, result),
                    Ok(Async::Ready(None)) => Ok(0),
                    Ok(Async::NotReady) => Err(Error::new(
                        ErrorKind::WouldBlock,
                        "Waiting on input to be available",
                    )),
                    Err(_) => Err(Error::new(ErrorKind::Other, "Read thread has stopped")),
                },
            },

            Err(_) => Err(ErrorKind::BrokenPipe.into()),
        }
    }
}

impl ::tokio_io::AsyncRead for AsyncRead {}

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

    use partial_io::{GenInterrupted, PartialAsyncRead, PartialOp, PartialWithErrors};
    use tokio_io::io::read_to_end;

    quickcheck! {
        fn partial_io(seq: PartialWithErrors<GenInterrupted>, input: Vec<u8>) -> bool {
            let mut core = ::tokio_core::reactor::Core::new().unwrap();

            let reader = async_read(&core.handle(), ::std::io::Cursor::new(input.clone()));
            let partial_reader = PartialAsyncRead::new(reader, seq);

            core.run(read_to_end(partial_reader, vec![])).ok().map(|t| t.1) == Some(input)
        }
    }

    #[test]
    fn partial_2_1() {
        let mut core = ::tokio_core::reactor::Core::new().unwrap();

        let input = vec![0, 0];
        let reader = async_read(&core.handle(), ::std::io::Cursor::new(input.clone()));
        let seq = vec![PartialOp::Limited(2), PartialOp::Limited(1)];
        let partial_reader = PartialAsyncRead::new(reader, seq);

        assert_eq!(
            core.run(read_to_end(partial_reader, vec![]))
                .ok()
                .map(|t| t.1),
            Some(input)
        );
    }
}
<|endoftext|>


<commit_before>//
// MSX CAS Packager
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate docopt;
extern crate rustc_serialize;

mod args;
mod tape;

#[allow(dead_code)]
fn main() {
    let action = args::parse_args().action();
    match action {
        args::Action::Version => print_version(),
        _ => {},
    };
}

fn print_version() {
    println!("MSX CAS Packager (MCP) v0.1.0");
    println!("Copyright (C) 2015 Alvaro Polo");
    println!("");
    println!("This program is subject to the terms of the Mozilla Public License v2.0.");
    println!("");
}
<commit_msg>Link the list functionality to the main program<commit_after>//
// MSX CAS Packager
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate docopt;
extern crate rustc_serialize;

mod args;
mod tape;

use std::fs::File;

#[allow(dead_code)]
fn main() {
    let action = args::parse_args().action();
    match action {
        args::Action::Version => print_version(),
        args::Action::List(path) => list_files(&path[..]),
    };
}

fn print_version() {
    println!("MSX CAS Packager (MCP) v0.1.0");
    println!("Copyright (C) 2015 Alvaro Polo");
    println!("");
    println!("This program is subject to the terms of the Mozilla Public License v2.0.");
    println!("");
}

fn list_files(path: &str) {
    let mut tape_file = match File::open(path) {
        Ok(f) => f,
        Err(e) => {
            println!("Cannot open file '{}': {}", path, e);
            return
        }
    };
    let tape = match tape::Tape::read(&mut tape_file) {
        Ok(f) => f,
        Err(e) => {
            println!("Cannot read file '{}': {}", path, e);
            return
        }
    };
    for file in tape.files() {
        match file {
            tape::File::Bin(name, begin, end, start, data) => {
                println!("bin    | {} | {:5} bytes | [0x{:x},0x{:x}]:0x{:x}",
                    name, data.len(), begin, end, start);
            },
            tape::File::Basic(name, data) => {
                println!("basic  | {} | {:5} bytes", name, data.len());
            },
            tape::File::Ascii(name, data) => {
                let nbytes = data.iter().fold(0, |size, chunk| size + chunk.len());
                println!("ascii  | {} | {:5} bytes", name, nbytes);
            },
            tape::File::Custom(data) => {
                println!("custom |        | {:5} bytes", data.len());
            }
        };
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;
extern crate extra;
extern crate syscall;

use std::env;
use std::io::{stdout, stderr, Write};
use coreutils::ArgParser;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{stat} */ r#"
NAME
    stat - display file status

SYNOPSIS
    stat [ -h | --help ] FILE...

DESCRIPTION
    Displays file status.

OPTIONS
    --help, -h
        print this message
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        return;
    }

    for path in &parser.args[0..] {
        let mut st = syscall::Stat::default();
        let fd = syscall::open(path, syscall::O_CLOEXEC | syscall::O_STAT).unwrap();
        syscall::fstat(fd, &mut st).unwrap();
        syscall::close(fd).unwrap();
        println!("File: {}", path);
        println!("Size: {}  Blocks: {}  IO Block: {}", st.st_size, st.st_blocks, st.st_blksize);
        println!("Device: {}  Inode: {}  Links: {}", st.st_dev, st.st_ino, st.st_nlink);
        println!("Access: {:o}  Uid: {}  Gid: {}", st.st_mode, st.st_uid, st.st_gid);
        println!("Access: {}.{:09}", st.st_atime, st.st_atime_nsec);
        println!("Modify: {}.{:09}", st.st_mtime, st.st_mtime_nsec);
        println!("Change: {}.{:09}", st.st_ctime, st.st_ctime_nsec);
    }
}
<commit_msg>Print file type in stat<commit_after>#![deny(warnings)]

extern crate coreutils;
extern crate extra;
extern crate syscall;

use std::env;
use std::io::{stdout, stderr, Write};
use coreutils::ArgParser;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{stat} */ r#"
NAME
    stat - display file status

SYNOPSIS
    stat [ -h | --help ] FILE...

DESCRIPTION
    Displays file status.

OPTIONS
    --help, -h
        print this message
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        return;
    }

    for path in &parser.args[0..] {
        let mut st = syscall::Stat::default();
        let fd = syscall::open(path, syscall::O_CLOEXEC | syscall::O_STAT).unwrap();
        syscall::fstat(fd, &mut st).unwrap();
        syscall::close(fd).unwrap();
        let file_type = match st.st_mode & syscall::MODE_TYPE {
            syscall::MODE_FILE => "regular file",
            syscall::MODE_DIR => "directory",
            syscall::MODE_SYMLINK => "symbolic link",
            _ => ""
        };
        println!("File: {}", path);
        println!("Size: {}  Blocks: {}  IO Block: {} {}", st.st_size, st.st_blocks, st.st_blksize, file_type);
        println!("Device: {}  Inode: {}  Links: {}", st.st_dev, st.st_ino, st.st_nlink);
        println!("Access: {:o}  Uid: {}  Gid: {}", st.st_mode, st.st_uid, st.st_gid);
        println!("Access: {}.{:09}", st.st_atime, st.st_atime_nsec);
        println!("Modify: {}.{:09}", st.st_mtime, st.st_mtime_nsec);
        println!("Change: {}.{:09}", st.st_ctime, st.st_ctime_nsec);
    }
}
<|endoftext|>


<commit_before>use reqwest::{ self, header };
use std::fs::File;
use std::io::{ BufWriter, Read, Write };
use std::path::Path;

use error::PackageError;

fn download_file<F>(url: &str, to_path: &Path, callback: F) -> Result<u64, PackageError>
    where F: Fn(u64, u64)
{
    // GET the URL, returning an error if necessary.
    let response = reqwest::get(url)?;

    // Try to retrieve the content length.
    let content_length =
        response
        .headers()
        .get::<header::ContentLength>()
        // If the Response contains no content-length, default to 0.
        .map_or(0u64, |x| {
            let header::ContentLength(len) = *x;
            len
        });

    // For every `BUFFER_SIZE` bytes, call the callback once.
    const BUFFER_SIZE: u64 = 65536;

    // Obviously, the target file to be written to by the BufWriter.
    let mut target = BufWriter::new(File::create(to_path)?);

    for (index, byte) in response.bytes().enumerate() {
        // Write to the target, returns an error if necessary.
        target.write(&[byte?]);

        // Checks whether it's time to call the callback, and call it if it is.
        // Plus one to `index` as `index` itself is zero-indexed.
        if index as u64 % BUFFER_SIZE == 0 {
            callback((index + 1) as u64, content_length);
        };
    }

    // In case the callback never got a chance to be called due to the package
    // itself being too small.
    callback(content_length, content_length);

    Ok(content_length)
}<commit_msg>The buffer_size is now configurable<commit_after>use reqwest::{ self, header };
use std::fs::File;
use std::io::{ BufWriter, Read, Write };
use std::path::Path;

use config::Config;
use error::PackageError;

fn download_file<F>(url: &str, to_path: &Path, callback: F) -> Result<u64, PackageError>
    where F: Fn(u64, u64)
{
    // GET the URL, returning an error if necessary.
    let response = reqwest::get(url)?;

    // Try to retrieve the content length.
    let content_length =
        response
        .headers()
        .get::<header::ContentLength>()
        // If the Response contains no content-length, default to 0.
        .map_or(0u64, |x| {
            let header::ContentLength(len) = *x;
            len
        });

    // For every `buffer_size` bytes, call the callback once.
    let Config { buffer_size: buffer_size, .. } = Config::default();

    // `buffer_size` decides how frequent the function calls the callback by
    // checking whether (downloaded bytes) % `buffer_size` is 0.
    let buffer_size = buffer_size.unwrap_or(65536);

    // Obviously, the target file to be written to by the BufWriter.
    let mut target = BufWriter::new(File::create(to_path)?);

    for (index, byte) in response.bytes().enumerate() {
        // Write to the target, returns an error if necessary.
        target.write(&[byte?]);

        // Checks whether it's time to call the callback, and call it if it is.
        // Plus one to `index` as `index` itself is zero-indexed.
        if index as u64 % buffer_size == 0 {
            callback((index + 1) as u64, content_length);
        };
    }

    // In case the callback never got a chance to be called due to the package
    // itself being too small.
    callback(content_length, content_length);

    Ok(content_length)
}<|endoftext|>


<commit_before>// If SIMD instructions are not available, this file provides a dummy implementation of Teddy that
// will compile, but do nothing at runtime.

use Match;

#[derive(Clone, Debug)]
pub struct Teddy;

impl Teddy {
    /// Create a new `Teddy` multi substring matcher.
    ///
    /// If a `Teddy` matcher could not be created (i.e., `pats` is empty or has
    /// an empty substring), then `None` is returned.
    ///
    /// # Warning
    ///
    /// If `teddy` was built without SIMD support, then this method will *always* return `None`.
    /// See the README for more information on how to compile `teddy` with SIMD support.
    pub fn new<'a, I>(_pats: I) -> Option<Teddy> where I: IntoIterator<Item=&'a [u8]> {
        None
    }

    /// Returns all of the substrings matched by this `Teddy`.
    pub fn patterns(&self) -> &[Vec<u8>] {
        unimplemented!();
    }

    /// Returns the approximate size on the heap used by this matcher.
    pub fn approximate_size(&self) -> usize {
        unimplemented!();
    }

    /// Searches `haystack` for the substrings in this `Teddy`. Returns the first match if one
    /// exists, and otherwise `None`.
    pub fn find(&self, _haystack: &[u8]) -> Option<Match> {
        unimplemented!();
    }

    /// Were we compiled with SIMD support? If not, `Teddy::new` will always just return `None`.
    ///
    /// See the README for more information on how to compile `teddy` with SIMD support.
    pub fn is_accelerated() -> bool {
        false
    }
}

<commit_msg>Add a missing docstring.<commit_after>// If SIMD instructions are not available, this file provides a dummy implementation of Teddy that
// will compile, but do nothing at runtime.

use Match;

/// A SIMD accelerated multi substring searcher.
#[derive(Clone, Debug)]
pub struct Teddy;

impl Teddy {
    /// Create a new `Teddy` multi substring matcher.
    ///
    /// If a `Teddy` matcher could not be created (i.e., `pats` is empty or has
    /// an empty substring), then `None` is returned.
    ///
    /// # Warning
    ///
    /// If `teddy` was built without SIMD support, then this method will *always* return `None`.
    /// See the README for more information on how to compile `teddy` with SIMD support.
    pub fn new<'a, I>(_pats: I) -> Option<Teddy> where I: IntoIterator<Item=&'a [u8]> {
        None
    }

    /// Returns all of the substrings matched by this `Teddy`.
    pub fn patterns(&self) -> &[Vec<u8>] {
        unimplemented!();
    }

    /// Returns the approximate size on the heap used by this matcher.
    pub fn approximate_size(&self) -> usize {
        unimplemented!();
    }

    /// Searches `haystack` for the substrings in this `Teddy`. Returns the first match if one
    /// exists, and otherwise `None`.
    pub fn find(&self, _haystack: &[u8]) -> Option<Match> {
        unimplemented!();
    }

    /// Were we compiled with SIMD support? If not, `Teddy::new` will always just return `None`.
    ///
    /// See the README for more information on how to compile `teddy` with SIMD support.
    pub fn is_accelerated() -> bool {
        false
    }
}

<|endoftext|>


<commit_before>use syntax::{ast, abi, ast_util, codemap};
use syntax::ptr::P;
use syntax::ext::base;
use syntax::parse::token;

use syntax::ext::build::AstBuilder;

use test::Test;
use bench::Bench;

use describe::{DescribeState, SubBlock};

/// Trait meaning something can be turned into an ast::Item with configuration.
pub trait Generate<Cfg> {
    /// Turn Self into an ast::Item with a configuration object.
    fn generate(self, codemap::Span, &mut base::ExtCtxt, Cfg) -> P<ast::Item>;
}

impl<'a> Generate<&'a DescribeState> for Test {
    fn generate(self, sp: codemap::Span, cx: &mut base::ExtCtxt, state: &'a DescribeState) -> P<ast::Item> {
        let Test { description, block, failing } = self;

        // Create the #[test] attribute.
        let test_attribute = cx.attribute(sp, cx.meta_word(sp, token::InternedString::new("test")));

        // Create the #[should_fail] attribute.
        let should_fail = cx.attribute(sp, cx.meta_word(sp, token::InternedString::new("should_fail")));

        let non_snake_word = cx.meta_word(sp, token::InternedString::new("non_snake_case"));
        let allow_non_snake_case = cx.meta_list(sp, token::InternedString::new("allow"),
                                                vec![non_snake_word]);
        let allow_non_snake_case = cx.attribute(sp, allow_non_snake_case);

        // Create the full test body by splicing in the statements and view items of the before and
        // after blocks if they are present.
        let test_body = match (&state.before_each, &state.after_each) {
            (&None, &None) => block,

            (&Some(ref before), &None) => {
                P(ast::Block {
                    view_items: before.view_items + block.view_items,
                    stmts: before.stmts + block.stmts,
                    ..block.deref().clone()
                })
            },

            (&None, &Some(ref after)) => {
                P(ast::Block {
                    view_items: block.view_items + after.view_items,
                    stmts: block.stmts + after.stmts,
                    ..block.deref().clone()
                })
            },

            (&Some(ref before), &Some(ref after)) => {
                P(ast::Block {
                    view_items: before.view_items + block.view_items + after.view_items,
                    stmts: before.stmts + block.stmts + after.stmts,
                    ..block.deref().clone()
                })
            }
        };

        // Constructing attributes:
        // #[test] - no way without it
        // #[allow(non_snake_case_attr)] as description may contain upper case
        // #[should_fail] if specified
        let mut attrs = vec![test_attribute, allow_non_snake_case];
        if failing {
            attrs.push(should_fail);
        }

        // Create the final Item that represents the test.
        P(ast::Item {
            // Name it with a snake_case version of the description.
            ident: cx.ident_of(description.replace(" ", "_").as_slice()),
            attrs: attrs,
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemFn(
                // Takes no arguments and returns ()
                cx.fn_decl(vec![], cx.ty(sp, ast::Ty_::TyTup(vec![]))),

                // All the usual types.
                ast::NormalFn,
                abi::Rust,
                ast_util::empty_generics(),

                // Add the body of the function.
                test_body
            ),
            // Inherited visibility (not pub)
            vis: ast::Inherited,
            span: sp
        })
    }
}

impl Generate<()> for Bench {
    fn generate(self, sp: codemap::Span, cx: &mut base::ExtCtxt, _: ()) -> P<ast::Item> {
        let Bench { bench, description, block } = self;

        // Create the #[bench] attribute.
        let bench_attribute = cx.attribute(sp, cx.meta_word(sp, token::InternedString::new("bench")));

        // Create the final Item that represents the benchmark.
        P(ast::Item {
            // Name it with a snake_case version of the description.
            ident: cx.ident_of(description.replace(" ", "_").as_slice()),

            // Add #[test] and possibly #[should_fail]
            attrs: vec![bench_attribute],
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemFn(
                // Takes one argument of &mut Bencher
                cx.fn_decl(vec![ast::Arg {
                    ty: quote_ty!(cx, &mut ::test::Bencher),
                    pat: quote_pat!(cx, $bench),
                    id: ast::DUMMY_NODE_ID
                }], cx.ty(sp, ast::Ty_::TyTup(vec![]))),

                // All the usual types.
                ast::NormalFn,
                abi::Rust,
                ast_util::empty_generics(),

                // Add the body of the function.
                block
            ),
            // Inherited visibility (not pub)
            vis: ast::Inherited,
            span: sp
        })
    }
}

impl<'a> Generate<&'a DescribeState> for SubBlock {
    fn generate(self, sp: codemap::Span, cx: &mut base::ExtCtxt, state: &'a DescribeState) -> P<ast::Item> {
        match self {
            SubBlock::Test(test) => test.generate(sp, cx, state),
            SubBlock::Bench(bench) => bench.generate(sp, cx, ()),
            SubBlock::Describe(item) => item.generate(sp, cx, ())
        }
    }
}

impl Generate<()> for DescribeState {
    fn generate(self, sp: codemap::Span, cx: &mut base::ExtCtxt, _: ()) -> P<ast::Item> {
        // Get the name of this mod.
        let name = self.name.clone().unwrap();

        // Create subblocks from a full DescribeState
        let subblocks = self.subblocks.clone().into_iter().map(|block| { block.generate(sp, cx, &self) }).collect();

        // Get a glob import of all items in scope to the module that `describe!` is called from.
        //
        // This glob is `pub use super::*` so that nested `describe!` blocks (which will also contain
        // this glob) will be able to see all the symbols.
        let super_glob = cx.view_use_glob(sp, ast::Public, vec![cx.ident_of("super")]);

        // Generate the new module.
        cx.item_mod(sp, sp, name, vec![], vec![super_glob], subblocks)
    }
}

<commit_msg>(chore) Use unqualified TyTup.<commit_after>use syntax::{ast, abi, ast_util, codemap};
use syntax::ptr::P;
use syntax::ext::base;
use syntax::parse::token;

use syntax::ext::build::AstBuilder;

use test::Test;
use bench::Bench;

use describe::{DescribeState, SubBlock};

/// Trait meaning something can be turned into an ast::Item with configuration.
pub trait Generate<Cfg> {
    /// Turn Self into an ast::Item with a configuration object.
    fn generate(self, codemap::Span, &mut base::ExtCtxt, Cfg) -> P<ast::Item>;
}

impl<'a> Generate<&'a DescribeState> for Test {
    fn generate(self, sp: codemap::Span, cx: &mut base::ExtCtxt, state: &'a DescribeState) -> P<ast::Item> {
        let Test { description, block, failing } = self;

        // Create the #[test] attribute.
        let test_attribute = cx.attribute(sp, cx.meta_word(sp, token::InternedString::new("test")));

        // Create the #[should_fail] attribute.
        let should_fail = cx.attribute(sp, cx.meta_word(sp, token::InternedString::new("should_fail")));

        let non_snake_word = cx.meta_word(sp, token::InternedString::new("non_snake_case"));
        let allow_non_snake_case = cx.meta_list(sp, token::InternedString::new("allow"),
                                                vec![non_snake_word]);
        let allow_non_snake_case = cx.attribute(sp, allow_non_snake_case);

        // Create the full test body by splicing in the statements and view items of the before and
        // after blocks if they are present.
        let test_body = match (&state.before_each, &state.after_each) {
            (&None, &None) => block,

            (&Some(ref before), &None) => {
                P(ast::Block {
                    view_items: before.view_items + block.view_items,
                    stmts: before.stmts + block.stmts,
                    ..block.deref().clone()
                })
            },

            (&None, &Some(ref after)) => {
                P(ast::Block {
                    view_items: block.view_items + after.view_items,
                    stmts: block.stmts + after.stmts,
                    ..block.deref().clone()
                })
            },

            (&Some(ref before), &Some(ref after)) => {
                P(ast::Block {
                    view_items: before.view_items + block.view_items + after.view_items,
                    stmts: before.stmts + block.stmts + after.stmts,
                    ..block.deref().clone()
                })
            }
        };

        // Constructing attributes:
        // #[test] - no way without it
        // #[allow(non_snake_case_attr)] as description may contain upper case
        // #[should_fail] if specified
        let mut attrs = vec![test_attribute, allow_non_snake_case];
        if failing {
            attrs.push(should_fail);
        }

        // Create the final Item that represents the test.
        P(ast::Item {
            // Name it with a snake_case version of the description.
            ident: cx.ident_of(description.replace(" ", "_").as_slice()),
            attrs: attrs,
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemFn(
                // Takes no arguments and returns ()
                cx.fn_decl(vec![], cx.ty(sp, ast::TyTup(vec![]))),

                // All the usual types.
                ast::NormalFn,
                abi::Rust,
                ast_util::empty_generics(),

                // Add the body of the function.
                test_body
            ),
            // Inherited visibility (not pub)
            vis: ast::Inherited,
            span: sp
        })
    }
}

impl Generate<()> for Bench {
    fn generate(self, sp: codemap::Span, cx: &mut base::ExtCtxt, _: ()) -> P<ast::Item> {
        let Bench { bench, description, block } = self;

        // Create the #[bench] attribute.
        let bench_attribute = cx.attribute(sp, cx.meta_word(sp, token::InternedString::new("bench")));

        // Create the final Item that represents the benchmark.
        P(ast::Item {
            // Name it with a snake_case version of the description.
            ident: cx.ident_of(description.replace(" ", "_").as_slice()),

            // Add #[test] and possibly #[should_fail]
            attrs: vec![bench_attribute],
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemFn(
                // Takes one argument of &mut Bencher
                cx.fn_decl(vec![ast::Arg {
                    ty: quote_ty!(cx, &mut ::test::Bencher),
                    pat: quote_pat!(cx, $bench),
                    id: ast::DUMMY_NODE_ID
                }], cx.ty(sp, ast::TyTup(vec![]))),

                // All the usual types.
                ast::NormalFn,
                abi::Rust,
                ast_util::empty_generics(),

                // Add the body of the function.
                block
            ),
            // Inherited visibility (not pub)
            vis: ast::Inherited,
            span: sp
        })
    }
}

impl<'a> Generate<&'a DescribeState> for SubBlock {
    fn generate(self, sp: codemap::Span, cx: &mut base::ExtCtxt, state: &'a DescribeState) -> P<ast::Item> {
        match self {
            SubBlock::Test(test) => test.generate(sp, cx, state),
            SubBlock::Bench(bench) => bench.generate(sp, cx, ()),
            SubBlock::Describe(item) => item.generate(sp, cx, ())
        }
    }
}

impl Generate<()> for DescribeState {
    fn generate(self, sp: codemap::Span, cx: &mut base::ExtCtxt, _: ()) -> P<ast::Item> {
        // Get the name of this mod.
        let name = self.name.clone().unwrap();

        // Create subblocks from a full DescribeState
        let subblocks = self.subblocks.clone().into_iter().map(|block| { block.generate(sp, cx, &self) }).collect();

        // Get a glob import of all items in scope to the module that `describe!` is called from.
        //
        // This glob is `pub use super::*` so that nested `describe!` blocks (which will also contain
        // this glob) will be able to see all the symbols.
        let super_glob = cx.view_use_glob(sp, ast::Public, vec![cx.ident_of("super")]);

        // Generate the new module.
        cx.item_mod(sp, sp, name, vec![], vec![super_glob], subblocks)
    }
}

<|endoftext|>


<commit_before>use glob::glob;
use hyper::client::HttpConnector;
use hyper::rt::{self, Future, Stream};
use hyper::{header, Body, Chunk, Client, Request, Response};
use hyper_tls::HttpsConnector;
use serde_json;
use statics::TEMP_DIRNAME;
use std;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use std::sync::mpsc;
use structs::{CliError, Config, Member, PublicKey, RateLimit, Repo, Sector, SectorGroup, Team};

pub struct GithubClient {
    pub conf: Config,
}

impl GithubClient {
    pub fn new(config: &Config) -> GithubClient {
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", &config.cert_path);
        }
        GithubClient { conf: config.clone() }
    }

    fn get_cache_path(url: &str) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push(TEMP_DIRNAME);
        path.push(url);
        path
    }

    fn load_contents_from_cache(&self, url: &str) -> Result<(std::fs::Metadata, String), CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut contents = String::new();
        f.read_to_string(&mut contents)?;
        Ok((metadata, contents))
    }

    fn store_contents_to_cache(&self, url: &str, contents: &str) -> Result<(), CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap_or(std::path::Path::new("/")))?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(contents.as_bytes())?;
        Ok(())
    }

    fn get_contents_from_url(&self, url: &str) -> Result<String, CliError> {
        let mut all_contents: Vec<serde_json::value::Value> = Vec::new();
        let mut page = 1;
        loop {
            let mut new_array = self.get_contents_from_url_page(url, page)?;
            if new_array.is_empty() {
                break;
            }
            all_contents.append(&mut new_array);
            page += 1;
        }
        let contents = serde_json::ser::to_string(&all_contents)?;
        self.store_contents_to_cache(url, &contents)?;
        Ok(contents)
    }

    fn build_request(&self, url: &str) -> Request<Body> {
        let token = String::from("token ") + &self.conf.token;
        Request::get(url).header(header::AUTHORIZATION, token.as_str())
                         .header(header::USER_AGENT, "sectora")
                         .body(Body::empty())
                         .expect("Request")
    }

    fn build_page_request(&self, url: &str, page: u64) -> Request<Body> {
        let sep = if url.contains("?") { "&" } else { "?" };
        let url_p = format!("{}{}page={}", url, sep, page);
        self.build_request(&url_p)
    }

    fn build_https_client() -> Client<HttpsConnector<HttpConnector>> {
        let https = HttpsConnector::new(4).expect("HttpsConnector");
        Client::builder().build(https)
    }

    fn run_request(&self, req: Request<Body>) -> Result<Chunk, CliError> {
        let client = Self::build_https_client();
        let concat_response = |res: Response<Body>| res.into_body().concat2();
        let (tx, rx) = mpsc::sync_channel(1);
        let etx = tx.clone();
        let send_response = move |r| tx.send(Ok(r)).expect("send response");
        let send_err = move |e| etx.send(Err(CliError::from(e))).expect("send err");
        rt::run(rt::lazy(move || {
                             client.request(req)
                                   .and_then(concat_response)
                                   .map(send_response)
                                   .map_err(send_err)
                         }));
        rx.recv().expect("recv response")
    }

    fn get_contents_from_url_page(&self, url: &str, page: u64) -> Result<Vec<serde_json::Value>, CliError> {
        let req = self.build_page_request(url, page);
        self.run_request(req).and_then(|body| serde_json::from_slice(&body).map_err(CliError::from))
    }

    fn get_contents(&self, url: &str) -> Result<String, CliError> {
        match self.load_contents_from_cache(url) {
            Ok((metadata, cache_contents)) => match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                Ok(caching_duration) => {
                    if caching_duration.as_secs() > self.conf.cache_duration {
                        match self.get_contents_from_url(url) {
                            Ok(contents_from_url) => Ok(contents_from_url),
                            Err(_) => Ok(cache_contents),
                        }
                    } else {
                        Ok(cache_contents)
                    }
                }
                Err(_) => Ok(cache_contents),
            },
            Err(_) => self.get_contents_from_url(url),
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user: &str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let contents = self.get_contents(&url)?;
        let keys = serde_json::from_str::<Vec<PublicKey>>(&contents)?;
        Ok(keys.iter().map(|k| k.key.clone()).collect::<Vec<String>>().join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user: &str) -> Result<bool, CliError> {
        let sectors = self.get_sectors()?;
        Ok(sectors.iter().any(|team| team.members.contains_key(user)))
    }

    pub fn get_sectors(&self) -> Result<Vec<SectorGroup>, CliError> {
        let mut sectors: Vec<SectorGroup> = self.get_teams_result()?;
        sectors.append(&mut self.get_repos_result()?);
        Ok(sectors)
    }

    fn get_teams_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_teams = self.get_team_map()?;
        let mut teams = Vec::new();
        for team_conf in &self.conf.team {
            if let &Some(gh_team) = &gh_teams.get(&team_conf.name) {
                teams.push(SectorGroup { sector: Sector::from(gh_team.clone()),
                                         gid: team_conf.gid.clone(),
                                         group: team_conf.group.clone(),
                                         members: self.get_team_members(gh_team.id)?, });
            }
        }
        Ok(teams)
    }

    fn get_team_map(&self) -> Result<HashMap<String, Team>, CliError> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, self.conf.org);
        let contents = self.get_contents(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(&contents)?;
        Ok(teams.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_team_members(&self, mid: u64) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/teams/{}/members", self.conf.endpoint, mid);
        let contents = self.get_contents(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&contents)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    fn get_repos_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_repos = self.get_repo_map()?;
        let mut repos = Vec::new();
        for repo_conf in &self.conf.repo {
            if let &Some(gh_repo) = &gh_repos.get(&repo_conf.name) {
                repos.push(SectorGroup { sector: Sector::from(gh_repo.clone()),
                                         gid: repo_conf.gid.clone(),
                                         group: repo_conf.group.clone(),
                                         members: self.get_repo_collaborators(&gh_repo.name)?, });
            }
        }
        Ok(repos)
    }

    fn get_repo_map(&self) -> Result<HashMap<String, Repo>, CliError> {
        let url = format!("{}/orgs/{}/repos", self.conf.endpoint, self.conf.org);
        let contents = self.get_contents(&url)?;
        let repos = serde_json::from_str::<Vec<Repo>>(&contents)?;
        Ok(repos.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_repo_collaborators(&self, repo_name: &str) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/repos/{}/{}/collaborators?affiliation=outside",
                          self.conf.endpoint, self.conf.org, repo_name);
        let contents = self.get_contents(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&contents)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    fn get_rate_limit(&self) -> Result<RateLimit, CliError> {
        let url = format!("{}/rate_limit", self.conf.endpoint);
        let req = self.build_request(&url);
        self.run_request(req).and_then(|body| serde_json::from_slice(&body).map_err(CliError::from))
    }

    #[allow(dead_code)]
    pub fn print_rate_limit(&self) -> Result<(), CliError> {
        let rate_limit = self.get_rate_limit()?;
        println!("{:?}", rate_limit);
        Ok(())
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push(TEMP_DIRNAME);
        path.push("**/*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {
                    if path.is_file() {
                        std::fs::remove_file(path)?
                    }
                }
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }
}
<commit_msg>Rename variables in run_request<commit_after>use glob::glob;
use hyper::client::HttpConnector;
use hyper::rt::{self, Future, Stream};
use hyper::{header, Body, Chunk, Client, Request, Response};
use hyper_tls::HttpsConnector;
use serde_json;
use statics::TEMP_DIRNAME;
use std;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use std::sync::mpsc;
use structs::{CliError, Config, Member, PublicKey, RateLimit, Repo, Sector, SectorGroup, Team};

pub struct GithubClient {
    pub conf: Config,
}

impl GithubClient {
    pub fn new(config: &Config) -> GithubClient {
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", &config.cert_path);
        }
        GithubClient { conf: config.clone() }
    }

    fn get_cache_path(url: &str) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push(TEMP_DIRNAME);
        path.push(url);
        path
    }

    fn load_contents_from_cache(&self, url: &str) -> Result<(std::fs::Metadata, String), CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut contents = String::new();
        f.read_to_string(&mut contents)?;
        Ok((metadata, contents))
    }

    fn store_contents_to_cache(&self, url: &str, contents: &str) -> Result<(), CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap_or(std::path::Path::new("/")))?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(contents.as_bytes())?;
        Ok(())
    }

    fn get_contents_from_url(&self, url: &str) -> Result<String, CliError> {
        let mut all_contents: Vec<serde_json::value::Value> = Vec::new();
        let mut page = 1;
        loop {
            let mut new_array = self.get_contents_from_url_page(url, page)?;
            if new_array.is_empty() {
                break;
            }
            all_contents.append(&mut new_array);
            page += 1;
        }
        let contents = serde_json::ser::to_string(&all_contents)?;
        self.store_contents_to_cache(url, &contents)?;
        Ok(contents)
    }

    fn build_request(&self, url: &str) -> Request<Body> {
        let token = String::from("token ") + &self.conf.token;
        Request::get(url).header(header::AUTHORIZATION, token.as_str())
                         .header(header::USER_AGENT, "sectora")
                         .body(Body::empty())
                         .expect("Request")
    }

    fn build_page_request(&self, url: &str, page: u64) -> Request<Body> {
        let sep = if url.contains("?") { "&" } else { "?" };
        let url_p = format!("{}{}page={}", url, sep, page);
        self.build_request(&url_p)
    }

    fn build_https_client() -> Client<HttpsConnector<HttpConnector>> {
        let https = HttpsConnector::new(4).expect("HttpsConnector");
        Client::builder().build(https)
    }

    fn run_request(&self, req: Request<Body>) -> Result<Chunk, CliError> {
        let concat_body = |res: Response<Body>| res.into_body().concat2();
        let (tx, rx) = mpsc::sync_channel(1);
        let ex = tx.clone();
        let send_res = move |r| tx.send(Ok(r)).expect("send response");
        let send_err = move |e| ex.send(Err(CliError::from(e))).expect("send err");
        let hc = Self::build_https_client();
        rt::run(rt::lazy(move || hc.request(req).and_then(concat_body).map(send_res).map_err(send_err)));
        rx.recv().expect("recv response")
    }

    fn get_contents_from_url_page(&self, url: &str, page: u64) -> Result<Vec<serde_json::Value>, CliError> {
        let req = self.build_page_request(url, page);
        self.run_request(req).and_then(|body| serde_json::from_slice(&body).map_err(CliError::from))
    }

    fn get_contents(&self, url: &str) -> Result<String, CliError> {
        match self.load_contents_from_cache(url) {
            Ok((metadata, cache_contents)) => match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                Ok(caching_duration) => {
                    if caching_duration.as_secs() > self.conf.cache_duration {
                        match self.get_contents_from_url(url) {
                            Ok(contents_from_url) => Ok(contents_from_url),
                            Err(_) => Ok(cache_contents),
                        }
                    } else {
                        Ok(cache_contents)
                    }
                }
                Err(_) => Ok(cache_contents),
            },
            Err(_) => self.get_contents_from_url(url),
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user: &str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let contents = self.get_contents(&url)?;
        let keys = serde_json::from_str::<Vec<PublicKey>>(&contents)?;
        Ok(keys.iter().map(|k| k.key.clone()).collect::<Vec<String>>().join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user: &str) -> Result<bool, CliError> {
        let sectors = self.get_sectors()?;
        Ok(sectors.iter().any(|team| team.members.contains_key(user)))
    }

    pub fn get_sectors(&self) -> Result<Vec<SectorGroup>, CliError> {
        let mut sectors: Vec<SectorGroup> = self.get_teams_result()?;
        sectors.append(&mut self.get_repos_result()?);
        Ok(sectors)
    }

    fn get_teams_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_teams = self.get_team_map()?;
        let mut teams = Vec::new();
        for team_conf in &self.conf.team {
            if let &Some(gh_team) = &gh_teams.get(&team_conf.name) {
                teams.push(SectorGroup { sector: Sector::from(gh_team.clone()),
                                         gid: team_conf.gid.clone(),
                                         group: team_conf.group.clone(),
                                         members: self.get_team_members(gh_team.id)?, });
            }
        }
        Ok(teams)
    }

    fn get_team_map(&self) -> Result<HashMap<String, Team>, CliError> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, self.conf.org);
        let contents = self.get_contents(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(&contents)?;
        Ok(teams.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_team_members(&self, mid: u64) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/teams/{}/members", self.conf.endpoint, mid);
        let contents = self.get_contents(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&contents)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    fn get_repos_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_repos = self.get_repo_map()?;
        let mut repos = Vec::new();
        for repo_conf in &self.conf.repo {
            if let &Some(gh_repo) = &gh_repos.get(&repo_conf.name) {
                repos.push(SectorGroup { sector: Sector::from(gh_repo.clone()),
                                         gid: repo_conf.gid.clone(),
                                         group: repo_conf.group.clone(),
                                         members: self.get_repo_collaborators(&gh_repo.name)?, });
            }
        }
        Ok(repos)
    }

    fn get_repo_map(&self) -> Result<HashMap<String, Repo>, CliError> {
        let url = format!("{}/orgs/{}/repos", self.conf.endpoint, self.conf.org);
        let contents = self.get_contents(&url)?;
        let repos = serde_json::from_str::<Vec<Repo>>(&contents)?;
        Ok(repos.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_repo_collaborators(&self, repo_name: &str) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/repos/{}/{}/collaborators?affiliation=outside",
                          self.conf.endpoint, self.conf.org, repo_name);
        let contents = self.get_contents(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&contents)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    fn get_rate_limit(&self) -> Result<RateLimit, CliError> {
        let url = format!("{}/rate_limit", self.conf.endpoint);
        let req = self.build_request(&url);
        self.run_request(req).and_then(|body| serde_json::from_slice(&body).map_err(CliError::from))
    }

    #[allow(dead_code)]
    pub fn print_rate_limit(&self) -> Result<(), CliError> {
        let rate_limit = self.get_rate_limit()?;
        println!("{:?}", rate_limit);
        Ok(())
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push(TEMP_DIRNAME);
        path.push("**/*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {
                    if path.is_file() {
                        std::fs::remove_file(path)?
                    }
                }
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! A Mach-o fat binary is a multi-architecture binary container

use core::fmt;

use std::fs::File;
use std::io::{self, Read};

use scroll::{self, Pread};
use mach::constants::cputype::{CpuType, CpuSubType, CPU_SUBTYPE_MASK, CPU_ARCH_ABI64};
use error;

pub const FAT_MAGIC: u32 = 0xcafebabe;
pub const FAT_CIGAM: u32 = 0xbebafeca;

#[repr(C)]
#[derive(Clone, Copy, Default)]
#[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))]
/// The Mach-o `FatHeader` always has its data bigendian
pub struct FatHeader {
    /// The magic number, `cafebabe`
    pub magic: u32,
    /// How many fat architecture headers there are
    pub nfat_arch: u32,
}

pub const SIZEOF_FAT_HEADER: usize = 8;

impl fmt::Debug for FatHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "0x{:x} nfat_arch: {}\n", self.magic, self.nfat_arch)
    }
}

impl FatHeader {
    /// Reinterpret a `FatHeader` from `bytes`
    pub fn from_bytes(bytes: &[u8; SIZEOF_FAT_HEADER]) -> FatHeader {
        let mut offset = 0;
        let magic = bytes.gread_with(&mut offset, scroll::BE).unwrap();
        let nfat_arch = bytes.gread_with(&mut offset, scroll::BE).unwrap();
        FatHeader {
            magic: magic,
            nfat_arch: nfat_arch,
        }
    }

    /// Reads a `FatHeader` from a `File` on disk
    pub fn from_fd(fd: &mut File) -> io::Result<FatHeader> {
        let mut header = [0; SIZEOF_FAT_HEADER];
        try!(fd.read(&mut header));
        Ok(FatHeader::from_bytes(&header))
    }

    /// Parse a mach-o fat header from the `bytes`
    pub fn parse(bytes: &[u8]) -> error::Result<FatHeader> {
        Ok(bytes.pread_with::<FatHeader>(0, scroll::BE)?)
    }

}

#[repr(C)]
#[derive(Clone, Copy, Default)]
#[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))]
/// The Mach-o `FatArch` always has its data bigendian
pub struct FatArch {
    /// What kind of CPU this binary is
    pub cputype: u32,
    pub cpusubtype: u32,
    /// Where in the fat binary it starts
    pub offset: u32,
    /// How big the binary is
    pub size: u32,
    pub align: u32,
}

pub const SIZEOF_FAT_ARCH: usize = 20;

impl fmt::Debug for FatArch {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("FatArch")
            .field("cputype", &self.cputype())
            .field("cmdsize", &self.cpusubtype())
            .field("offset",  &format_args!("{:#x}", &self.offset))
            .field("size",    &self.size)
            .field("align",   &self.align)
            .finish()
    }
}

impl FatArch {
    /// Get the slice of bytes this header describes from `bytes`
    pub fn slice<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
        let start = self.offset as usize;
        let end = (self.offset + self.size) as usize;
        &bytes[start..end]
    }

    /// Returns the cpu type
    pub fn cputype(&self) -> CpuType {
        self.cputype
    }

    /// Returns the cpu subtype with the capabilities removed
    pub fn cpusubtype(&self) -> CpuSubType {
        self.cpusubtype & !CPU_SUBTYPE_MASK
    }

    /// Returns the capabilities of the CPU
    pub fn cpu_caps(&self) -> u32 {
        (self.cpusubtype & CPU_SUBTYPE_MASK) >> 24
    }

    /// Whether this fat architecture header describes a 64-bit binary
    pub fn is_64(&self) -> bool {
        (self.cputype & CPU_ARCH_ABI64) != 0
    }

    /// Parse a `FatArch` header from `bytes` at `offset`
    pub fn parse(bytes: &[u8], offset: usize) -> error::Result<Self> {
        let arch = bytes.pread_with::<FatArch>(offset, scroll::BE)?;
        Ok(arch)
    }
}
<commit_msg>Correct the is_64 check for fat archs<commit_after>//! A Mach-o fat binary is a multi-architecture binary container

use core::fmt;

use std::fs::File;
use std::io::{self, Read};

use scroll::{self, Pread};
use mach::constants::cputype::{CpuType, CpuSubType, CPU_SUBTYPE_MASK, CPU_ARCH_ABI64};
use error;

pub const FAT_MAGIC: u32 = 0xcafebabe;
pub const FAT_CIGAM: u32 = 0xbebafeca;

#[repr(C)]
#[derive(Clone, Copy, Default)]
#[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))]
/// The Mach-o `FatHeader` always has its data bigendian
pub struct FatHeader {
    /// The magic number, `cafebabe`
    pub magic: u32,
    /// How many fat architecture headers there are
    pub nfat_arch: u32,
}

pub const SIZEOF_FAT_HEADER: usize = 8;

impl fmt::Debug for FatHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "0x{:x} nfat_arch: {}\n", self.magic, self.nfat_arch)
    }
}

impl FatHeader {
    /// Reinterpret a `FatHeader` from `bytes`
    pub fn from_bytes(bytes: &[u8; SIZEOF_FAT_HEADER]) -> FatHeader {
        let mut offset = 0;
        let magic = bytes.gread_with(&mut offset, scroll::BE).unwrap();
        let nfat_arch = bytes.gread_with(&mut offset, scroll::BE).unwrap();
        FatHeader {
            magic: magic,
            nfat_arch: nfat_arch,
        }
    }

    /// Reads a `FatHeader` from a `File` on disk
    pub fn from_fd(fd: &mut File) -> io::Result<FatHeader> {
        let mut header = [0; SIZEOF_FAT_HEADER];
        try!(fd.read(&mut header));
        Ok(FatHeader::from_bytes(&header))
    }

    /// Parse a mach-o fat header from the `bytes`
    pub fn parse(bytes: &[u8]) -> error::Result<FatHeader> {
        Ok(bytes.pread_with::<FatHeader>(0, scroll::BE)?)
    }

}

#[repr(C)]
#[derive(Clone, Copy, Default)]
#[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))]
/// The Mach-o `FatArch` always has its data bigendian
pub struct FatArch {
    /// What kind of CPU this binary is
    pub cputype: u32,
    pub cpusubtype: u32,
    /// Where in the fat binary it starts
    pub offset: u32,
    /// How big the binary is
    pub size: u32,
    pub align: u32,
}

pub const SIZEOF_FAT_ARCH: usize = 20;

impl fmt::Debug for FatArch {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("FatArch")
            .field("cputype", &self.cputype())
            .field("cmdsize", &self.cpusubtype())
            .field("offset",  &format_args!("{:#x}", &self.offset))
            .field("size",    &self.size)
            .field("align",   &self.align)
            .finish()
    }
}

impl FatArch {
    /// Get the slice of bytes this header describes from `bytes`
    pub fn slice<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
        let start = self.offset as usize;
        let end = (self.offset + self.size) as usize;
        &bytes[start..end]
    }

    /// Returns the cpu type
    pub fn cputype(&self) -> CpuType {
        self.cputype
    }

    /// Returns the cpu subtype with the capabilities removed
    pub fn cpusubtype(&self) -> CpuSubType {
        self.cpusubtype & !CPU_SUBTYPE_MASK
    }

    /// Returns the capabilities of the CPU
    pub fn cpu_caps(&self) -> u32 {
        (self.cpusubtype & CPU_SUBTYPE_MASK) >> 24
    }

    /// Whether this fat architecture header describes a 64-bit binary
    pub fn is_64(&self) -> bool {
        (self.cputype & CPU_ARCH_ABI64) == CPU_ARCH_ABI64
    }

    /// Parse a `FatArch` header from `bytes` at `offset`
    pub fn parse(bytes: &[u8], offset: usize) -> error::Result<Self> {
        let arch = bytes.pread_with::<FatArch>(offset, scroll::BE)?;
        Ok(arch)
    }
}
<|endoftext|>