<commit_before>use error::Error;
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::{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), Error> {
        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<(), Error> {
        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_all(contents.as_bytes())?;
        Ok(())
    }

    fn get_contents_from_url(&self, url: &str) -> Result<String, Error> {
        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) -> Result<Request<Body>, Error> {
        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())
                         .map_err(Error::from)
    }

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

    fn build_https_client() -> Result<Client<HttpsConnector<HttpConnector>>, Error> {
        Ok(Client::builder().build(HttpsConnector::new(4)?))
    }

    fn run_request(&self, req: Request<Body>) -> Result<Chunk, Error> {
        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(Error::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>, Error> {
        let req = self.build_page_request(url, page)?;
        self.run_request(req)
            .and_then(|body| serde_json::from_slice(&body).map_err(Error::from))
    }

    fn get_contents(&self, url: &str) -> Result<String, Error> {
        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<(), Error> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, Error> {
        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, Error> {
        let sectors = self.get_sectors()?;
        Ok(sectors.iter().any(|team| team.members.contains_key(user)))
    }

    pub fn get_sectors(&self) -> Result<Vec<SectorGroup>, Error> {
        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>, Error> {
        let gh_teams = self.get_team_map(&self.conf.org)?;
        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,
                                         group: team_conf.group.clone(),
                                         members: self.get_team_members(gh_team.id)? });
            }
        }
        Ok(teams)
    }

    fn get_team_map(&self, org: &str) -> Result<HashMap<String, Team>, Error> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, 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>, Error> {
        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>, Error> {
        let gh_repos = self.get_repo_map(&self.conf.org)?;
        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,
                                         group: repo_conf.group.clone(),
                                         members: self.get_repo_collaborators(&gh_repo.name)? });
            }
        }
        Ok(repos)
    }

    fn get_repo_map(&self, org: &str) -> Result<HashMap<String, Repo>, Error> {
        let url = format!("{}/orgs/{}/repos", self.conf.endpoint, 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>, Error> {
        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, Error> {
        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(Error::from))
    }

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

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), Error> {
        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>Refactor<commit_after>use error::Error;
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::{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), Error> {
        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<(), Error> {
        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_all(contents.as_bytes())?;
        Ok(())
    }

    fn get_contents_from_url(&self, url: &str) -> Result<String, Error> {
        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) -> Result<Request<Body>, Error> {
        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())
                         .map_err(Error::from)
    }

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

    fn build_https_client() -> Result<Client<HttpsConnector<HttpConnector>>, Error> {
        Ok(Client::builder().build(HttpsConnector::new(4)?))
    }

    fn run_request(&self, req: Request<Body>) -> Result<Chunk, Error> {
        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(Error::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>, Error> {
        let req = self.build_page_request(url, page)?;
        self.run_request(req)
            .and_then(|body| serde_json::from_slice(&body).map_err(Error::from))
    }

    fn get_contents(&self, url: &str) -> Result<String, Error> {
        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<(), Error> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, Error> {
        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, Error> {
        let sectors = self.get_sectors()?;
        Ok(sectors.iter().any(|team| team.members.contains_key(user)))
    }

    pub fn get_sectors(&self) -> Result<Vec<SectorGroup>, Error> {
        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>, Error> {
        let gh_teams = self.get_team_map(&self.conf.org)?;
        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,
                                         group: team_conf.group.clone(),
                                         members: self.get_team_members(gh_team.id)? });
            }
        }
        Ok(teams)
    }

    fn get_team_map(&self, org: &str) -> Result<HashMap<String, Team>, Error> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, 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>, Error> {
        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>, Error> {
        let gh_repos = self.get_repo_map(&self.conf.org)?;
        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,
                                         group: repo_conf.group.clone(),
                                         members: self.get_repo_collaborators(&self.conf.org, &gh_repo.name)? });
            }
        }
        Ok(repos)
    }

    fn get_repo_map(&self, org: &str) -> Result<HashMap<String, Repo>, Error> {
        let url = format!("{}/orgs/{}/repos", self.conf.endpoint, 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, org: &str, repo_name: &str) -> Result<HashMap<String, Member>, Error> {
        let url = format!("{}/repos/{}/{}/collaborators?affiliation=outside",
                          self.conf.endpoint, 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, Error> {
        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(Error::from))
    }

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

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), Error> {
        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>use gl;
use gl::types::*;
use std::mem;
//! OpenGL arrays of verticies, all shaded with the same program.
use std::ptr;
use std::raw;
use libc::types::common::c95;
use vertex;

/// Gets the id number for a given input of the shader program.
#[allow(non_snake_case_functions)]
unsafe fn glGetAttribLocation(shader_program: GLuint, name: &str) -> GLint {
  name.with_c_str(|ptr| gl::GetAttribLocation(shader_program, ptr))
}

unsafe fn aligned_slice_to_ptr<T>(vs: &[T], alignment: uint) -> *const c95::c_void {
  let vs_as_slice : raw::Slice<T> = mem::transmute(vs);
  assert_eq!(vs_as_slice.data as uint & (alignment - 1), 0);
  vs_as_slice.data as *const c95::c_void
}

/// A fixed-capacity array of GLfloat-based structures passed to OpenGL.
pub struct GLBuffer<T> {
  vertex_array: u32,
  vertex_buffer: u32,
  length: uint,
  capacity: uint,
}

impl<T: Clone> GLBuffer<T> {
  #[inline]
  /// An empty `GLBuffer`.
  pub unsafe fn null() -> GLBuffer<T> {
    GLBuffer {
      vertex_array: -1 as u32,
      vertex_buffer: -1 as u32,
      length: 0,
      capacity: 0,
    }
  }

  #[inline]
  /// Creates a new array of objects on the GPU.
  pub unsafe fn new(shader_program: GLuint, attribs: &[vertex::AttribData], capacity: uint) -> GLBuffer<T> {
    let mut vertex_array = 0;
    let mut vertex_buffer = 0;
    gl::GenVertexArrays(1, &mut vertex_array);
    gl::GenBuffers(1, &mut vertex_buffer);

    gl::BindVertexArray(vertex_array);
    gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);

    let mut offset = 0;
    for attrib in attribs.iter() {
      let shader_attrib = glGetAttribLocation(shader_program, attrib.name) as GLuint;
      assert!(shader_attrib != -1, "shader attribute \"{}\" not found", attrib.name);

      gl::EnableVertexAttribArray(shader_attrib);
      gl::VertexAttribPointer(
          shader_attrib,
          attrib.size as i32,
          gl::FLOAT,
          gl::FALSE as GLboolean,
          mem::size_of::<T>() as i32,
          ptr::null().offset(offset),
      );
      offset += (attrib.size * mem::size_of::<GLfloat>()) as int;
    }

    // Check that the attribs are sized correctly.
    assert_eq!(offset, mem::size_of::<T>() as int);

    gl::BufferData(
      gl::ARRAY_BUFFER,
      (capacity * mem::size_of::<T>()) as GLsizeiptr,
      ptr::null(),
      gl::DYNAMIC_DRAW,
    );

    GLBuffer {
      vertex_array: vertex_array,
      vertex_buffer: vertex_buffer,
      length: 0,
      capacity: capacity,
    }
  }

  /// Analog of vec::Vector::swap_remove`, but for GLBuffer data.
  pub unsafe fn swap_remove(&mut self, span: uint, i: uint) {
    gl::BindVertexArray(self.vertex_array);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer);

    self.length -= span;
    let size = mem::size_of::<T>();
    let copy_size = (size * span) as uint;
    let mut bytes: Vec<T> = Vec::with_capacity(span);
    bytes.set_len(span);
    gl::GetBufferSubData(
      gl::ARRAY_BUFFER,
      (self.length * size) as i64,
      copy_size as i64,
      mem::transmute(&bytes.as_mut_slice()[0]),
    );
    gl::BufferSubData(
      gl::ARRAY_BUFFER,
      (i * copy_size) as i64,
      copy_size as i64,
      aligned_slice_to_ptr(bytes.slice(0, span), 4),
    );
  }

  #[inline]
  /// Add a set of triangles to the set of triangles to render.
  pub unsafe fn push(&mut self, vs: &[T]) {
    if self.length + vs.len() > self.capacity {
      fail!("GLBuffer::push: {} into a {}/{} full GLbuffer", vs.len(), self.length, self.capacity);
    }

    gl::BindVertexArray(self.vertex_array);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer);

    let size = mem::size_of::<T>() as i64;
    gl::BufferSubData(
      gl::ARRAY_BUFFER,
      size * self.length as i64,
      size * vs.len() as i64,
      aligned_slice_to_ptr(vs, 4)
    );

    self.length += vs.len();
  }

  #[inline]
  /// Draws all the queued triangles to the screen.
  pub fn draw(&self, mode: GLenum) {
    self.draw_slice(mode, 0, self.length);
  }

  /// Draw some subset of the triangle array.
  pub fn draw_slice(&self, mode: GLenum, start: uint, len: uint) {
    gl::BindVertexArray(self.vertex_array);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer);

    gl::DrawArrays(mode, start as i32, len as i32);
  }
}

#[unsafe_destructor]
impl<T> Drop for GLBuffer<T> {
  #[inline]
  fn drop(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer);
      gl::DeleteVertexArrays(1, &self.vertex_array);
    }
  }
}
<commit_msg>fixed build<commit_after>//! OpenGL arrays of verticies, all shaded with the same program.
use gl;
use gl::types::*;
use std::mem;
use std::ptr;
use std::raw;
use libc::types::common::c95;
use vertex;

/// Gets the id number for a given input of the shader program.
#[allow(non_snake_case_functions)]
unsafe fn glGetAttribLocation(shader_program: GLuint, name: &str) -> GLint {
  name.with_c_str(|ptr| gl::GetAttribLocation(shader_program, ptr))
}

unsafe fn aligned_slice_to_ptr<T>(vs: &[T], alignment: uint) -> *const c95::c_void {
  let vs_as_slice : raw::Slice<T> = mem::transmute(vs);
  assert_eq!(vs_as_slice.data as uint & (alignment - 1), 0);
  vs_as_slice.data as *const c95::c_void
}

/// A fixed-capacity array of GLfloat-based structures passed to OpenGL.
pub struct GLBuffer<T> {
  vertex_array: u32,
  vertex_buffer: u32,
  length: uint,
  capacity: uint,
}

impl<T: Clone> GLBuffer<T> {
  #[inline]
  /// An empty `GLBuffer`.
  pub unsafe fn null() -> GLBuffer<T> {
    GLBuffer {
      vertex_array: -1 as u32,
      vertex_buffer: -1 as u32,
      length: 0,
      capacity: 0,
    }
  }

  #[inline]
  /// Creates a new array of objects on the GPU.
  pub unsafe fn new(shader_program: GLuint, attribs: &[vertex::AttribData], capacity: uint) -> GLBuffer<T> {
    let mut vertex_array = 0;
    let mut vertex_buffer = 0;
    gl::GenVertexArrays(1, &mut vertex_array);
    gl::GenBuffers(1, &mut vertex_buffer);

    gl::BindVertexArray(vertex_array);
    gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);

    let mut offset = 0;
    for attrib in attribs.iter() {
      let shader_attrib = glGetAttribLocation(shader_program, attrib.name) as GLuint;
      assert!(shader_attrib != -1, "shader attribute \"{}\" not found", attrib.name);

      gl::EnableVertexAttribArray(shader_attrib);
      gl::VertexAttribPointer(
          shader_attrib,
          attrib.size as i32,
          gl::FLOAT,
          gl::FALSE as GLboolean,
          mem::size_of::<T>() as i32,
          ptr::null().offset(offset),
      );
      offset += (attrib.size * mem::size_of::<GLfloat>()) as int;
    }

    // Check that the attribs are sized correctly.
    assert_eq!(offset, mem::size_of::<T>() as int);

    gl::BufferData(
      gl::ARRAY_BUFFER,
      (capacity * mem::size_of::<T>()) as GLsizeiptr,
      ptr::null(),
      gl::DYNAMIC_DRAW,
    );

    GLBuffer {
      vertex_array: vertex_array,
      vertex_buffer: vertex_buffer,
      length: 0,
      capacity: capacity,
    }
  }

  /// Analog of vec::Vector::swap_remove`, but for GLBuffer data.
  pub unsafe fn swap_remove(&mut self, span: uint, i: uint) {
    gl::BindVertexArray(self.vertex_array);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer);

    self.length -= span;
    let size = mem::size_of::<T>();
    let copy_size = (size * span) as uint;
    let mut bytes: Vec<T> = Vec::with_capacity(span);
    bytes.set_len(span);
    gl::GetBufferSubData(
      gl::ARRAY_BUFFER,
      (self.length * size) as i64,
      copy_size as i64,
      mem::transmute(&bytes.as_mut_slice()[0]),
    );
    gl::BufferSubData(
      gl::ARRAY_BUFFER,
      (i * copy_size) as i64,
      copy_size as i64,
      aligned_slice_to_ptr(bytes.slice(0, span), 4),
    );
  }

  #[inline]
  /// Add a set of triangles to the set of triangles to render.
  pub unsafe fn push(&mut self, vs: &[T]) {
    if self.length + vs.len() > self.capacity {
      fail!("GLBuffer::push: {} into a {}/{} full GLbuffer", vs.len(), self.length, self.capacity);
    }

    gl::BindVertexArray(self.vertex_array);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer);

    let size = mem::size_of::<T>() as i64;
    gl::BufferSubData(
      gl::ARRAY_BUFFER,
      size * self.length as i64,
      size * vs.len() as i64,
      aligned_slice_to_ptr(vs, 4)
    );

    self.length += vs.len();
  }

  #[inline]
  /// Draws all the queued triangles to the screen.
  pub fn draw(&self, mode: GLenum) {
    self.draw_slice(mode, 0, self.length);
  }

  /// Draw some subset of the triangle array.
  pub fn draw_slice(&self, mode: GLenum, start: uint, len: uint) {
    gl::BindVertexArray(self.vertex_array);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer);

    gl::DrawArrays(mode, start as i32, len as i32);
  }
}

#[unsafe_destructor]
impl<T> Drop for GLBuffer<T> {
  #[inline]
  fn drop(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer);
      gl::DeleteVertexArrays(1, &self.vertex_array);
    }
  }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::io::{self, Write};
use std::rc::Rc;
use std::str;
use std::sync::{Arc, Mutex};
use std::thread;

use common::driver::ErrorDestination;
use errors::{self, DiagnosticBuilder, Handler};
use errors::emitter::{ColorConfig, Emitter, EmitterWriter};
use parser::ast::Stmt;
use parser::ast::StmtKind::*;
use parser::codemap::CodeMap;
use parser::lexer::{Reader, StringReader};
use parser::parser::{filemap_to_parser, parse_tts_from_source_str, ParseSess, Parser, PResult};
use parser::tokenstream::TokenTree;

use self::ErrorKind::*;

pub enum IncrCompilerAction {
  Done,
  Error,
  Continue,
  Quit
}

enum ErrorKind {
  UnclosedDelimiter,
  Unknown
}

unsafe impl Send for IncrCompilerAction {}

pub struct IncrCompiler {
  pub filename: String,
  pub errdst: Rc<RefCell<ErrorDestination>>, // error destination
}

impl IncrCompiler {
  pub fn new(filename: String, errdst: Rc<RefCell<ErrorDestination>>)
      -> IncrCompiler {

    IncrCompiler {
      filename: filename,
      errdst: errdst
    }
  }

  pub fn eval(&mut self, line: &str) -> IncrCompilerAction {

    // Temporarily have stack size set to 16MB to deal with nom-using crates failing
    const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB

    struct Sink(Arc<Mutex<Vec<u8>>>);
    impl Write for Sink {
        fn write(&mut self, data: &[u8]) -> io::Result<usize> {
            Write::write(&mut *self.0.lock().unwrap(), data)
        }
        fn flush(&mut self) -> io::Result<()> {
            Ok(())
        }
    }

    let data = Arc::new(Mutex::new(Vec::new()));
    let err = Sink(data.clone());
    let errdst = self.errdst.borrow().clone();
    let line = line.to_owned();
    let filename = self.filename.clone();

    let task = thread::Builder::new().name("parsing".to_owned());
    let handle = task.spawn(move || {

      io::set_panic(Some(Box::new(err)));

      let cm = Rc::new(CodeMap::new());
      let (emitter, errs) = new_emitter(errdst, cm.clone());
      let handler = Handler::with_emitter(true, false, emitter);
      let parsess = ParseSess::with_span_handler(handler, cm.clone());
      let filemap = parsess.codemap().new_filemap_and_lines(&filename, None, &line);
      let mut parser = filemap_to_parser(&parsess, filemap);

      if need_more_liens(&errs) {
        return IncrCompilerAction::Continue;
      } else if is_error(&errs) {
        return IncrCompilerAction::Error;
      }

      IncrCompilerAction::Done
    }).unwrap();

    let action = match handle.join() {
      Ok(result) => result,
      Err(value) => {
        if !value.is::<errors::FatalError>() {
          writeln!(io::stderr(), "{}", str::from_utf8(&data.lock().unwrap()).unwrap()).unwrap();
        }
        IncrCompilerAction::Error
      }
    };

    action
  }
}

fn need_more_liens(errs: &Rc<RefCell<Vec<ErrorKind>>>) -> bool {
  errs.borrow().len() == 1 && match errs.borrow()[0] {
    UnclosedDelimiter => true,
    _ => false
  }
}

fn is_error(errs: &Rc<RefCell<Vec<ErrorKind>>>) -> bool {
  if errs.borrow().len() == 0 {
    return false;
  }

  if errs.borrow().len() > 2 {
    return true;
  }

  // only if errors.len() == 1
  match errs.borrow()[0] {
    UnclosedDelimiter => false,
    _ => true
  }
}

fn new_emitter(errdst: ErrorDestination, cm: Rc<CodeMap>)
      -> (Box<Emitter>, Rc<RefCell<Vec<ErrorKind>>>) {
    let ew = match errdst {
      ErrorDestination::Stderr => {
        EmitterWriter::stderr(ColorConfig::Auto, Some(cm))
      }
      ErrorDestination::Raw(ref buf) => {
        let delegator = WriteDelegator {write: buf.clone()};
        EmitterWriter::new(Box::new(delegator), Some(cm))
      }
    };

    let (emitter, errkinds) = EmitterDelegator::new(ew);
    (Box::new(emitter), errkinds)
}

pub struct WriteDelegator {
  write: Rc<RefCell<Box<io::Write + Send>>>
}

unsafe impl Send for WriteDelegator {}

impl io::Write for WriteDelegator {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    self.write.borrow_mut().write(buf)
  }

  fn flush(&mut self) -> io::Result<()> {
    self.write.borrow_mut().flush()
  }
}

struct EmitterDelegator {
  em: EmitterWriter,
  errors: Rc<RefCell<Vec<ErrorKind>>>
}

impl EmitterDelegator {
  pub fn new(em : EmitterWriter)
      -> (EmitterDelegator, Rc<RefCell<Vec<ErrorKind>>>) {
    let errors = Rc::new(RefCell::new(Vec::new()));
    let delegator = EmitterDelegator { em : em, errors: errors.clone() };
    (delegator, errors)
  }
}

impl Emitter for EmitterDelegator {
  fn emit(&mut self, db: &DiagnosticBuilder) {

    let errkind = error_kind(db.message());

    match errkind {
      UnclosedDelimiter => {},
      _ => self.em.emit(db)
    };

    self.errors.borrow_mut().push(errkind);
  }
}

fn error_kind(msg: &str) -> ErrorKind {
  if is_unclosed_delemiter(msg) {
    ErrorKind::UnclosedDelimiter
  } else {
    Unknown
  }
}

fn is_unclosed_delemiter(msg: &str) -> bool {
  msg == "this file contains an un-closed delimiter"
}<commit_msg>Implement more meta structures.<commit_after>use std::cell::RefCell;
use std::io::{self, Write};
use std::rc::Rc;
use std::str;
use std::sync::{Arc, Mutex};
use std::thread;

use common::driver::ErrorDestination;
use errors::{self, DiagnosticBuilder, Handler};
use errors::emitter::{ColorConfig, Emitter, EmitterWriter};
use parser::ast::{self, Stmt};
use parser::ast::StmtKind::*;
use parser::codemap::CodeMap;
use parser::lexer::{Reader, StringReader};
use parser::parser::{filemap_to_parser, parse_tts_from_source_str, ParseSess, Parser, PResult};
use parser::ptr::P;
use parser::tokenstream::TokenTree;

use self::ErrorKind::*;

pub enum IncrCompilerAction {
  Done,
  Error,
  Continue,
  Quit
}

enum ErrorKind {
  UnclosedDelimiter,
  Unknown
}

enum Parsed {
  Item(P<ast::Item>),
  Stmt(ast::Stmt),
  None,
  Error
}

unsafe impl Send for IncrCompilerAction {}

pub struct IncrCompiler {
  pub filename: String,
  pub errdst: Rc<RefCell<ErrorDestination>>, // error destination
}

impl IncrCompiler {
  pub fn new(filename: String, errdst: Rc<RefCell<ErrorDestination>>)
      -> IncrCompiler {

    IncrCompiler {
      filename: filename,
      errdst: errdst
    }
  }

  pub fn eval(&mut self, line: &str) -> IncrCompilerAction {

    // Temporarily have stack size set to 16MB to deal with nom-using crates failing
    const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB

    struct Sink(Arc<Mutex<Vec<u8>>>);
    impl Write for Sink {
        fn write(&mut self, data: &[u8]) -> io::Result<usize> {
            Write::write(&mut *self.0.lock().unwrap(), data)
        }
        fn flush(&mut self) -> io::Result<()> {
            Ok(())
        }
    }

    let data = Arc::new(Mutex::new(Vec::new()));
    let err = Sink(data.clone());
    let errdst = self.errdst.borrow().clone();
    let line = line.to_owned();
    let filename = self.filename.clone();

    let task = thread::Builder::new().name("parsing".to_owned());
    let handle = task.spawn(move || {

      io::set_panic(Some(Box::new(err)));

      let cm = Rc::new(CodeMap::new());
      let (emitter, errs) = new_emitter(errdst, cm.clone());
      let handler = Handler::with_emitter(true, false, emitter);
      let parsess = ParseSess::with_span_handler(handler, cm.clone());
      let filemap = parsess.codemap().new_filemap_and_lines(&filename, None, &line);
      let mut parser = filemap_to_parser(&parsess, filemap);

      if need_more_liens(&errs) {
        return IncrCompilerAction::Continue;
      } else if is_error(&errs) {
        return IncrCompilerAction::Error;
      }

      IncrCompilerAction::Done
    }).unwrap();

    let action = match handle.join() {
      Ok(result) => result,
      Err(value) => {
        if !value.is::<errors::FatalError>() {
          writeln!(io::stderr(), "{}", str::from_utf8(&data.lock().unwrap()).unwrap()).unwrap();
        }
        IncrCompilerAction::Error
      }
    };

    action
  }
}

fn parse(parser: &mut Parser) -> Parsed {
  let parsed: Option<Parsed> = match parser.parse_item() {
    Ok(Some(item)) => Parsed::Item(item),
    Ok(None) => None,
    Err(ref mut e) => {
      e.cancel();
      None
     }
  };

  let parsed = if parsed.is_none() {
    match parser.parse_full_stmt() {
      Ok(Some(item)) => Parsed::Item(item),
      Ok(None) => None,
      Err(ref mut e) => {
        e.cancel();
        None
      }
    }
  }

  parsed
}

fn need_more_liens(errs: &Rc<RefCell<Vec<ErrorKind>>>) -> bool {
  errs.borrow().len() == 1 && match errs.borrow()[0] {
    UnclosedDelimiter => true,
    _ => false
  }
}

fn is_error(errs: &Rc<RefCell<Vec<ErrorKind>>>) -> bool {
  if errs.borrow().len() == 0 {
    return false;
  }

  if errs.borrow().len() > 2 {
    return true;
  }

  // only if errors.len() == 1
  match errs.borrow()[0] {
    UnclosedDelimiter => false,
    _ => true
  }
}

fn new_emitter(errdst: ErrorDestination, cm: Rc<CodeMap>)
      -> (Box<Emitter>, Rc<RefCell<Vec<ErrorKind>>>) {
    let ew = match errdst {
      ErrorDestination::Stderr => {
        EmitterWriter::stderr(ColorConfig::Auto, Some(cm))
      }
      ErrorDestination::Raw(ref buf) => {
        let delegator = WriteDelegator {write: buf.clone()};
        EmitterWriter::new(Box::new(delegator), Some(cm))
      }
    };

    let (emitter, errkinds) = EmitterDelegator::new(ew);
    (Box::new(emitter), errkinds)
}

pub struct WriteDelegator {
  write: Rc<RefCell<Box<io::Write + Send>>>
}

unsafe impl Send for WriteDelegator {}

impl io::Write for WriteDelegator {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    self.write.borrow_mut().write(buf)
  }

  fn flush(&mut self) -> io::Result<()> {
    self.write.borrow_mut().flush()
  }
}

struct EmitterDelegator {
  em: EmitterWriter,
  errors: Rc<RefCell<Vec<ErrorKind>>>
}

impl EmitterDelegator {
  pub fn new(em : EmitterWriter)
      -> (EmitterDelegator, Rc<RefCell<Vec<ErrorKind>>>) {
    let errors = Rc::new(RefCell::new(Vec::new()));
    let delegator = EmitterDelegator { em : em, errors: errors.clone() };
    (delegator, errors)
  }
}

impl Emitter for EmitterDelegator {
  fn emit(&mut self, db: &DiagnosticBuilder) {

    let errkind = error_kind(db.message());

    match errkind {
      UnclosedDelimiter => {},
      _ => self.em.emit(db)
    };

    self.errors.borrow_mut().push(errkind);
  }
}

fn error_kind(msg: &str) -> ErrorKind {
  if is_unclosed_delemiter(msg) {
    ErrorKind::UnclosedDelimiter
  } else {
    Unknown
  }
}

fn is_unclosed_delemiter(msg: &str) -> bool {
  msg == "this file contains an un-closed delimiter"
}<|endoftext|>


<commit_before>#![allow(dead_code)]

use crate::deserialize::FromSqlRow;
use crate::expression::AsExpression;
use std::time::SystemTime;

#[derive(AsExpression, FromSqlRow)]
#[diesel(foreign_derive)]
#[diesel(sql_type = crate::sql_types::Timestamp)]
struct SystemTimeProxy(SystemTime);

#[cfg(feature = "chrono")]
mod chrono {
    extern crate chrono;
    use self::chrono::*;
    use crate::deserialize::FromSqlRow;
    use crate::expression::AsExpression;
    use crate::sql_types::{Date, Time, Timestamp};

    #[derive(AsExpression, FromSqlRow)]
    #[diesel(foreign_derive)]
    #[diesel(sql_type = Date)]
    struct NaiveDateProxy(NaiveDate);

    #[derive(AsExpression, FromSqlRow)]
    #[diesel(foreign_derive)]
    #[diesel(sql_type = Time)]
    struct NaiveTimeProxy(NaiveTime);

    #[derive(AsExpression, FromSqlRow)]
    #[diesel(foreign_derive)]
    #[diesel(sql_type = Timestamp)]
    #[cfg_attr(
        feature = "postgres_backend",
        diesel(sql_type = crate::sql_types::Timestamptz)
    )]
    #[cfg_attr(feature = "mysql_backend", diesel(sql_type = crate::sql_types::Datetime))]
    // TODO: Add TimestamptzSqlite stuff here??
    struct NaiveDateTimeProxy(NaiveDateTime);

    #[derive(FromSqlRow)]
    #[diesel(foreign_derive)]
    #[cfg_attr(
        feature = "postgres_backend",
        derive(AsExpression),
        diesel(sql_type = crate::sql_types::Timestamptz)
    )]
    #[cfg_attr(feature = "sqlite", derive(AsExpression), diesel(sql_type = crate::sql_types::TimestamptzSqlite))]
    struct DateTimeProxy<Tz: TimeZone>(DateTime<Tz>);
}
<commit_msg>need to give sql_type<commit_after>#![allow(dead_code)]

use crate::deserialize::FromSqlRow;
use crate::expression::AsExpression;
use std::time::SystemTime;

#[derive(AsExpression, FromSqlRow)]
#[diesel(foreign_derive)]
#[diesel(sql_type = crate::sql_types::Timestamp)]
struct SystemTimeProxy(SystemTime);

#[cfg(feature = "chrono")]
mod chrono {
    extern crate chrono;
    use self::chrono::*;
    use crate::deserialize::FromSqlRow;
    use crate::expression::AsExpression;
    use crate::sql_types::{Date, Time, Timestamp};

    #[derive(AsExpression, FromSqlRow)]
    #[diesel(foreign_derive)]
    #[diesel(sql_type = Date)]
    struct NaiveDateProxy(NaiveDate);

    #[derive(AsExpression, FromSqlRow)]
    #[diesel(foreign_derive)]
    #[diesel(sql_type = Time)]
    struct NaiveTimeProxy(NaiveTime);

    #[derive(AsExpression, FromSqlRow)]
    #[diesel(foreign_derive)]
    #[diesel(sql_type = Timestamp)]
    #[cfg_attr(
        feature = "postgres_backend",
        diesel(sql_type = crate::sql_types::Timestamptz)
    )]
    #[cfg_attr(feature = "mysql_backend", diesel(sql_type = crate::sql_types::Datetime))]
    #[cfg_attr(feature = "sqlite", diesel(sql_type = crate::sql_types::TimestamptzSqlite))]
    struct NaiveDateTimeProxy(NaiveDateTime);

    #[derive(AsExpression, FromSqlRow)]
    #[diesel(foreign_derive)]
    #[diesel(sql_type = Timestamp)]
    #[cfg_attr(
        feature = "postgres_backend",
        diesel(sql_type = crate::sql_types::Timestamptz)
    )]
    #[cfg_attr(feature = "sqlite", diesel(sql_type = crate::sql_types::TimestamptzSqlite))]
    struct DateTimeProxy<Tz: TimeZone>(DateTime<Tz>);
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

use error_chain::ChainedError;
use libc::*;
use std::cmp;
use std::ffi::{CStr, CString};
use std::sync::RwLock;

use command;
use dl;
use errors::*;
use function::Function;

lazy_static!{
    pub static ref POINTERS: RwLock<Pointers> = RwLock::new(Pointers::default());
}

#[derive(Debug, Default)]
pub struct Pointers {
    RunListenServer: Function<unsafe extern "C" fn(*mut c_void,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_void,
                                                   *mut c_void)
                                                   -> c_int>,

    Cmd_AddCommand: Function<unsafe extern "C" fn(*const c_char, *mut c_void)>,
    Cmd_Argc: Function<unsafe extern "C" fn() -> c_int>,
    Cmd_Argv: Function<unsafe extern "C" fn(c_int) -> *const c_char>,
    Con_Printf: Function<unsafe extern "C" fn(*const c_char)>,
    Memory_Init: Function<unsafe extern "C" fn(*mut c_void, c_int)>,
}

/// This is the "main" function of hw.so, called inside CEngineAPI::Run().
/// The game runs within this function and shortly after it exits hw.so is unloaded.
/// Note: _restart also causes this function to exit, in this case the launcher
/// unloads and reloads hw.so and this function is called again as if it was a fresh start.
#[export_name = "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_"]
pub extern "C" fn RunListenServer(instance: *mut c_void,
                                  basedir: *mut c_char,
                                  cmdline: *mut c_char,
                                  postRestartCmdLineArgs: *mut c_char,
                                  launcherFactory: *mut c_void,
                                  filesystemFactory: *mut c_void)
                                  -> c_int {
    // hw.so just loaded, either for the first time or potentially at a different address.
    // Refresh all pointers.
    if let Err(ref e) = refresh_pointers().chain_err(|| "error refreshing pointers") {
        panic!("{}", e.display());
    }

    let rv = unsafe {
        real!(RunListenServer)(instance,
                               basedir,
                               cmdline,
                               postRestartCmdLineArgs,
                               launcherFactory,
                               filesystemFactory)
    };

    // Since hw.so is getting unloaded, reset all pointers.
    reset_pointers();

    rv
}

/// This function initializes the hunk memory.
/// After the hunk memory is initialized we can register console commands and variables.
#[no_mangle]
pub extern "C" fn Memory_Init(buf: *mut c_void, size: c_int) {
    let rv = unsafe { real!(Memory_Init)(buf, size) };

    unsafe {
        register_cvars_and_commands();
    }

    rv
}

/// Open hw.so, then get and store all necessary function and variable addresses.
fn refresh_pointers() -> Result<()> {
    let hw = dl::open("hw.so", RTLD_NOW | RTLD_NOLOAD)
        .chain_err(|| "couldn't load hw.so")?;

    let mut pointers = POINTERS.write().unwrap();

    unsafe {
        find!(pointers,
              hw,
              RunListenServer,
              "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_");
        find!(pointers, hw, Cmd_AddCommand, "Cmd_AddCommand");
        find!(pointers, hw, Cmd_Argc, "Cmd_Argc");
        find!(pointers, hw, Cmd_Argv, "Cmd_Argv");
        find!(pointers, hw, Con_Printf, "Con_Printf");
        find!(pointers, hw, Memory_Init, "Memory_Init");
    }

    Ok(())
}

/// Reset all pointers to their default values.
fn reset_pointers() {
    *POINTERS.write().unwrap() = Pointers::default();
}

/// Register console commands and variables.
/// Unsafe because it should only be called from the main game thread.
unsafe fn register_cvars_and_commands() {
    for cmd in command::COMMANDS.read().unwrap().iter() {
        register_command(cmd.name(), cmd.callback());
    }
}

/// Register a console command.
/// Unsafe because it should only be called from the main game thread.
unsafe fn register_command(name: &'static [u8], callback: extern "C" fn()) {
    real!(Cmd_AddCommand)(name as *const _ as *const _, callback as *mut c_void);
}

/// Print the given string to the game console. String must not contain null bytes.
/// Unsafe because it should only be called from the main game thread.
pub unsafe fn con_print(string: &str) {
    real!(Con_Printf)(CString::new(string.replace('%', "%%"))
                          .expect("string cannot contain null bytes")
                          .as_ptr())
}

/// Get the console command argument count.
/// Unsafe because it should only be called from the main game thread.
pub unsafe fn cmd_argc() -> u32 {
    let argc = real!(Cmd_Argc)();
    cmp::max(0, argc) as u32
}

/// Get a console command argument.
/// Unsafe because it should only be called from the main game thread.
pub unsafe fn cmd_argv(index: u32) -> String {
    let index = cmp::min(index, i32::max_value() as u32) as i32;
    let arg = real!(Cmd_Argv)(index);
    let string = CStr::from_ptr(arg).to_string_lossy().into_owned();
    string
}

command!(cap_test, |engine| {
    let args = engine.args();

    let mut buf = String::new();
    buf.push_str(&format!("Args len: {}\n", args.len()));

    for arg in args {
        buf.push_str(&arg);
        buf.push('\n');
    }

    engine.con_print(&buf);
});

command!(cap_another_test, |engine| {
    engine.con_print("Hello! %s %d %\n");
});
<commit_msg>Mark hook functions as unsafe<commit_after>#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

use error_chain::ChainedError;
use libc::*;
use std::cmp;
use std::ffi::{CStr, CString};
use std::sync::RwLock;

use command;
use dl;
use errors::*;
use function::Function;

lazy_static!{
    pub static ref POINTERS: RwLock<Pointers> = RwLock::new(Pointers::default());
}

#[derive(Debug, Default)]
pub struct Pointers {
    RunListenServer: Function<unsafe extern "C" fn(*mut c_void,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_void,
                                                   *mut c_void)
                                                   -> c_int>,

    Cmd_AddCommand: Function<unsafe extern "C" fn(*const c_char, *mut c_void)>,
    Cmd_Argc: Function<unsafe extern "C" fn() -> c_int>,
    Cmd_Argv: Function<unsafe extern "C" fn(c_int) -> *const c_char>,
    Con_Printf: Function<unsafe extern "C" fn(*const c_char)>,
    Memory_Init: Function<unsafe extern "C" fn(*mut c_void, c_int)>,
}

/// This is the "main" function of hw.so, called inside CEngineAPI::Run().
/// The game runs within this function and shortly after it exits hw.so is unloaded.
/// Note: _restart also causes this function to exit, in this case the launcher
/// unloads and reloads hw.so and this function is called again as if it was a fresh start.
#[export_name = "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_"]
pub unsafe extern "C" fn RunListenServer(instance: *mut c_void,
                                  basedir: *mut c_char,
                                  cmdline: *mut c_char,
                                  postRestartCmdLineArgs: *mut c_char,
                                  launcherFactory: *mut c_void,
                                  filesystemFactory: *mut c_void)
                                  -> c_int {
    // hw.so just loaded, either for the first time or potentially at a different address.
    // Refresh all pointers.
    if let Err(ref e) = refresh_pointers().chain_err(|| "error refreshing pointers") {
        panic!("{}", e.display());
    }

    let rv = real!(RunListenServer)(instance,
                                    basedir,
                                    cmdline,
                                    postRestartCmdLineArgs,
                                    launcherFactory,
                                    filesystemFactory);

    // Since hw.so is getting unloaded, reset all pointers.
    reset_pointers();

    rv
}

/// This function initializes the hunk memory.
/// After the hunk memory is initialized we can register console commands and variables.
#[no_mangle]
pub unsafe extern "C" fn Memory_Init(buf: *mut c_void, size: c_int) {
    let rv = real!(Memory_Init)(buf, size);

    register_cvars_and_commands();

    rv
}

/// Open hw.so, then get and store all necessary function and variable addresses.
fn refresh_pointers() -> Result<()> {
    let hw = dl::open("hw.so", RTLD_NOW | RTLD_NOLOAD)
        .chain_err(|| "couldn't load hw.so")?;

    let mut pointers = POINTERS.write().unwrap();

    unsafe {
        find!(pointers,
              hw,
              RunListenServer,
              "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_");
        find!(pointers, hw, Cmd_AddCommand, "Cmd_AddCommand");
        find!(pointers, hw, Cmd_Argc, "Cmd_Argc");
        find!(pointers, hw, Cmd_Argv, "Cmd_Argv");
        find!(pointers, hw, Con_Printf, "Con_Printf");
        find!(pointers, hw, Memory_Init, "Memory_Init");
    }

    Ok(())
}

/// Reset all pointers to their default values.
fn reset_pointers() {
    *POINTERS.write().unwrap() = Pointers::default();
}

/// Register console commands and variables.
/// Unsafe because it should only be called from the main game thread.
unsafe fn register_cvars_and_commands() {
    for cmd in command::COMMANDS.read().unwrap().iter() {
        register_command(cmd.name(), cmd.callback());
    }
}

/// Register a console command.
/// Unsafe because it should only be called from the main game thread.
unsafe fn register_command(name: &'static [u8], callback: extern "C" fn()) {
    real!(Cmd_AddCommand)(name as *const _ as *const _, callback as *mut c_void);
}

/// Print the given string to the game console. String must not contain null bytes.
/// Unsafe because it should only be called from the main game thread.
pub unsafe fn con_print(string: &str) {
    real!(Con_Printf)(CString::new(string.replace('%', "%%"))
                          .expect("string cannot contain null bytes")
                          .as_ptr())
}

/// Get the console command argument count.
/// Unsafe because it should only be called from the main game thread.
pub unsafe fn cmd_argc() -> u32 {
    let argc = real!(Cmd_Argc)();
    cmp::max(0, argc) as u32
}

/// Get a console command argument.
/// Unsafe because it should only be called from the main game thread.
pub unsafe fn cmd_argv(index: u32) -> String {
    let index = cmp::min(index, i32::max_value() as u32) as i32;
    let arg = real!(Cmd_Argv)(index);
    let string = CStr::from_ptr(arg).to_string_lossy().into_owned();
    string
}

command!(cap_test, |engine| {
    let args = engine.args();

    let mut buf = String::new();
    buf.push_str(&format!("Args len: {}\n", args.len()));

    for arg in args {
        buf.push_str(&arg);
        buf.push('\n');
    }

    engine.con_print(&buf);
});

command!(cap_another_test, |engine| {
    engine.con_print("Hello! %s %d %\n");
});
<|endoftext|>


<commit_before>use std::process::Command;
pub fn set(new_hostname: &String) -> bool {
    Command::new("hostname")
        .arg(new_hostname)
        .output()
        .is_ok()
}
<commit_msg>This commit improves: - Set hostname only when it is different. Resolves #23<commit_after>use std::process::Command;

pub fn get() -> Option<String> {
    let output = Command::new("hostname").output().unwrap();
    if output.status.success() {
        let hostname_with_newline = String::from_utf8(output.stdout).unwrap();
        Some(hostname_with_newline.replace("\n", ""))
    } else {
        None
    }
}

pub fn set(new_hostname: &String) -> bool {
    let current_hostname = get();
    match current_hostname {
        Some(hn) => {
            if hn == new_hostname.to_string() {
                return true
            } else {
                let output = Command::new("hostname")
                    .arg(new_hostname)
                    .output()
                    .unwrap();
                output.status.success()
            }
        },
        None => false
    }
}
<|endoftext|>


<commit_before>use libc::{self, c_int, O_EXCL, O_RDWR, O_CREAT, O_CLOEXEC};
use libc::stat as stat_t;
use std::os::unix::ffi::OsStrExt;
use std::ffi::CString;
use std::io;
use std::os::unix::io::{RawFd, FromRawFd, AsRawFd};
use std::fs::{self, File, OpenOptions};
use std::path::Path;
use util;

// Stolen from std.
pub fn cstr(path: &Path) -> io::Result<CString> {
    // TODO: Use OsStr::to_cstring (convert)
    CString::new(path.as_os_str().as_bytes()).map_err(|_|
        io::Error::new(io::ErrorKind::InvalidInput, "path contained a null"))
}

pub fn create_named(path: &Path) -> io::Result<File> {
    unsafe {
        let path = try!(cstr(path));
        match libc::open(
            path.as_ptr() as *const libc::c_char,
            O_CLOEXEC | O_EXCL | O_RDWR | O_CREAT,
            0o600) {
            -1 => Err(io::Error::last_os_error()),
            fd => Ok(FromRawFd::from_raw_fd(fd)),
        }
    }
}

#[cfg(target_os = "linux")]
pub fn create(dir: &Path) -> io::Result<File> {
    const O_TMPFILE: libc::c_int = 0o20200000;
    match unsafe {
        let path = try!(cstr(dir));
        libc::open(
            path.as_ptr() as *const libc::c_char,
            O_CLOEXEC | O_EXCL | O_TMPFILE | O_RDWR,
            0o600)
    } {
        -1 => create_unix(dir),
        fd => Ok(unsafe { FromRawFd::from_raw_fd(fd) }),
    }
}

#[cfg(not(target_os = "linux"))]
pub fn create(dir: &Path) -> io::Result<File> {
    create_unix(dir)
}

fn create_unix(dir: &Path) -> io::Result<File> {
    for _ in 0..::NUM_RETRIES {
        let tmp_path = dir.join(util::tmpname(".tmp", "", ::NUM_RAND_CHARS));
        return match create_named(&tmp_path) {
            Ok(file) => {
                // I should probably tell the user this failed but the temporary file creation
                // didn't really fail...
                let _ = fs::remove_file(tmp_path);
                Ok(file)
            },
            Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
            Err(e) => Err(e),
        }
    }
    Err(io::Error::new(io::ErrorKind::AlreadyExists,
                       "too many temporary directories already exist"))
}

unsafe fn stat(fd: RawFd) -> io::Result<stat_t> {
    let mut meta: stat_t = ::std::mem::zeroed();
    if libc::fstat(fd, &mut meta as *mut stat_t) != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(meta)
    }
}

pub fn reopen(file: &File, path: &Path) -> io::Result<File> {
    let new_file = try!(OpenOptions::new().read(true).write(true).open(path));
    unsafe {
        let old_meta = try!(stat(file.as_raw_fd()));
        let new_meta = try!(stat(new_file.as_raw_fd()));
        if old_meta.st_dev != new_meta.st_dev ||
           old_meta.st_ino != new_meta.st_ino {
            return Err(io::Error::new(io::ErrorKind::NotFound, "original tempfile has been replaced"));
        }
        Ok(new_file)
    }
}

pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
    unsafe {
        let old_path = try!(cstr(old_path));
        let new_path = try!(cstr(new_path));
        if overwrite {
            if libc::rename(old_path.as_ptr(), new_path.as_ptr()) != 0 {
                return Err(io::Error::last_os_error())
            }
        } else {
            if libc::link(old_path.as_ptr(), new_path.as_ptr()) != 0 {
                return Err(io::Error::last_os_error());
            }
            // Ignore unlink errors. Can we do better?
            // On recent linux, we can use renameat2 to do this atomically.
            let _ = libc::unlink(old_path.as_ptr());
        }
        Ok(())
    }
}
<commit_msg>imp/unix: always cast cstr.as_ptr() to avoid issues with differing c_char types<commit_after>use libc::{self, c_int, O_EXCL, O_RDWR, O_CREAT, O_CLOEXEC};
use libc::stat as stat_t;
use std::os::unix::ffi::OsStrExt;
use std::ffi::CString;
use std::io;
use std::os::unix::io::{RawFd, FromRawFd, AsRawFd};
use std::fs::{self, File, OpenOptions};
use std::path::Path;
use util;

// Stolen from std.
pub fn cstr(path: &Path) -> io::Result<CString> {
    // TODO: Use OsStr::to_cstring (convert)
    CString::new(path.as_os_str().as_bytes()).map_err(|_|
        io::Error::new(io::ErrorKind::InvalidInput, "path contained a null"))
}

pub fn create_named(path: &Path) -> io::Result<File> {
    unsafe {
        let path = try!(cstr(path));
        match libc::open(
            path.as_ptr() as *const libc::c_char,
            O_CLOEXEC | O_EXCL | O_RDWR | O_CREAT,
            0o600) {
            -1 => Err(io::Error::last_os_error()),
            fd => Ok(FromRawFd::from_raw_fd(fd)),
        }
    }
}

#[cfg(target_os = "linux")]
pub fn create(dir: &Path) -> io::Result<File> {
    const O_TMPFILE: libc::c_int = 0o20200000;
    match unsafe {
        let path = try!(cstr(dir));
        libc::open(
            path.as_ptr() as *const libc::c_char,
            O_CLOEXEC | O_EXCL | O_TMPFILE | O_RDWR,
            0o600)
    } {
        -1 => create_unix(dir),
        fd => Ok(unsafe { FromRawFd::from_raw_fd(fd) }),
    }
}

#[cfg(not(target_os = "linux"))]
pub fn create(dir: &Path) -> io::Result<File> {
    create_unix(dir)
}

fn create_unix(dir: &Path) -> io::Result<File> {
    for _ in 0..::NUM_RETRIES {
        let tmp_path = dir.join(util::tmpname(".tmp", "", ::NUM_RAND_CHARS));
        return match create_named(&tmp_path) {
            Ok(file) => {
                // I should probably tell the user this failed but the temporary file creation
                // didn't really fail...
                let _ = fs::remove_file(tmp_path);
                Ok(file)
            },
            Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
            Err(e) => Err(e),
        }
    }
    Err(io::Error::new(io::ErrorKind::AlreadyExists,
                       "too many temporary directories already exist"))
}

unsafe fn stat(fd: RawFd) -> io::Result<stat_t> {
    let mut meta: stat_t = ::std::mem::zeroed();
    if libc::fstat(fd, &mut meta as *mut stat_t) != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(meta)
    }
}

pub fn reopen(file: &File, path: &Path) -> io::Result<File> {
    let new_file = try!(OpenOptions::new().read(true).write(true).open(path));
    unsafe {
        let old_meta = try!(stat(file.as_raw_fd()));
        let new_meta = try!(stat(new_file.as_raw_fd()));
        if old_meta.st_dev != new_meta.st_dev ||
           old_meta.st_ino != new_meta.st_ino {
            return Err(io::Error::new(io::ErrorKind::NotFound, "original tempfile has been replaced"));
        }
        Ok(new_file)
    }
}

pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
    unsafe {
        let old_path = try!(cstr(old_path));
        let new_path = try!(cstr(new_path));
        if overwrite {
            if libc::rename(old_path.as_ptr() as *const libc::c_char,
                            new_path.as_ptr() as *const libc::c_char) != 0 {
                return Err(io::Error::last_os_error())
            }
        } else {
            if libc::link(old_path.as_ptr() as *const libc::c_char,
                          new_path.as_ptr() as *const libc::c_char) != 0 {
                return Err(io::Error::last_os_error());
            }
            // Ignore unlink errors. Can we do better?
            // On recent linux, we can use renameat2 to do this atomically.
            let _ = libc::unlink(old_path.as_ptr() as *const libc::c_char);
        }
        Ok(())
    }
}
<|endoftext|>


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

use super::Spawner;

mod collect;
mod enumerate;
mod filter;
mod map;
mod zip;

pub use self::collect::Combine;

/// A parallel iterator which works by splitting the underlying data
/// and sharing it between threads.
///
/// Functions which consume the iterator will take a `&Spawner` as an argument,
/// so that they can distribute their work in parallel.
pub trait SplitIterator: Sized {
    /// The item this iterator produces.
    type Item;

    /// The splittable base data which this consists of.
    type Base: Split;

    /// A consumer which can act as an ad-hoc iterator adapter
    /// chain while being shared across threads.
    type Consumer: Consumer<Self::Base, Item=Self::Item>;

    /// Destructure this iterator into a splittable base and
    /// a shareable consumer of that base.
    fn destructure(self) -> (Self::Base, Self::Consumer);

    /// Enumerate items by their index.
    fn enumerate(self) -> Enumerate<Self> {
        Enumerate {
            parent: self,
            off: 0,
        }
    }

    /// Filter items by some predicate.
    fn filter<F: Sync>(self, pred: F) -> Filter<Self, F> where F: Fn(&Self::Item) -> bool {
        Filter {
            parent: self,
            pred: pred,
        }
    }

    /// Map the items of this iterator to another type using the supplied function.
    fn map<F: Sync, U>(self, map: F) -> Map<Self, F> where F: Fn(Self::Item) -> U {
        Map {
            parent: self,
            map: map,
        }
    }

    /// Zip this iterator with another, combining their items
    /// in a tuple.
    fn zip<B: IntoSplitIterator>(self, other: B) -> Zip<Self, B::SplitIter> {
        Zip {
            a: self,
            b: other.into_split_iter(),
        }
    }

    /// Consume this iterator, performing an action for each item.
    fn for_each<F: Sync>(self, spawner: &Spawner, f: F) where F: Fn(Self::Item) {
        let (base, consumer) = self.destructure();

        let f = &f;
        consume_helper::<Self, _>((base, &consumer), spawner, &(|base, cons| {
            cons.consume(base, f);
        }))
    }

    /// Collect the items of this iterator into a combinable collection.
    ///
    /// Note that this works by repeatedly combining the results of `from_iter`,
    /// so this will probably lead to more allocations than a single-threaded
    /// iterator `collect`.
    fn collect<T: Send>(self, spawner: &Spawner) -> T
    where Self::Item: Send, T: FromIterator<Self::Item> + Combine + Send {
        collect::collect(self, spawner)
    }

    /// A lower and optional upper bound on the size of this iterator.
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, None)
    }
}

fn consume_helper<T: SplitIterator, F: Sync>(iter: (T::Base, &T::Consumer), spawner: &Spawner, f: &F)
where F: Fn(T::Base, &T::Consumer) {
    let (base, consumer) = iter;
    if let Some(idx) = base.should_split(1.0) {
        let (b1, b2) = base.split(idx);
        spawner.join(
            |inner| consume_helper::<T, F>((b1, consumer), inner, f),
            |inner| consume_helper::<T, F>((b2, consumer), inner, f),
        );
    } else {
        f(base, consumer);
    }
}

/// An iterator for which the exact number of elements is known.
///
/// If this is implemented for an iterator,`size_hint` for that iterator
/// must return a pair of the exact size.
pub trait ExactSizeSplitIterator: SplitIterator {
    /// Get the number of elements in this iterator.
    fn size(&self) -> usize;
}

/// Enumerate iterator adapter
pub struct Enumerate<T> {
    parent: T,
    off: usize,
}

/// Filter ilterator adapter.
///
/// This filters each element by a given predicate.
pub struct Filter<T, F> {
    parent: T,
    pred: F,
}

/// Map iterator adapter.
///
/// This transforms each element into a new object.
pub struct Map<T, F> {
    parent: T,
    map: F,
}

/// Zip iterator adapter.
///
/// This combines two other iterators into one.
pub struct Zip<A, B> {
    a: A,
    b: B,
}

/// Data which can be split in two at an index.
pub trait Split: Send + IntoIterator {
    /// Whether this should split.
    ///
    /// This is given a multiplier, which tells you to treat the data
    /// as "mul" times as large as it is. The reason for this is that
    /// each iterator adapter makes producing an individual item more expensive.
    /// As the cost of producing each item goes up, we want to split the data
    /// into more parallelizable jobs so we can get better work distribution
    /// across threads.
    ///
    /// For example, should_split(1.0) for slices returns Some only
    /// when then length of the slice is over 4096. This means
    /// that `should_split(2.0)` will return Some when the length
    /// of the slice is over 2048.
    fn should_split(&self, mul: f32) -> Option<usize>;

    /// Split the data at the specified index.
    /// Note that this may not always be the same as the index
    /// you return from should_split.
    fn split(self, usize) -> (Self, Self);

    /// A hint for the size of this data, containing
    /// a known lower bound (potentially zero) and an optional upper bound.
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, None)
    }
}

impl<T: Split> SplitIterator for T {
    type Item = T::Item;
    type Base = Self;
    type Consumer = ();

    fn destructure(self) -> (Self, ()) {
        (self, ())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        Split::size_hint(self)
    }
}

/// Things that can be turned into a `SplitIterator`.
pub trait IntoSplitIterator {
    /// The item the split iterator will produce.
    type Item;

    /// The iterator this will turn into.
    type SplitIter: SplitIterator<Item=Self::Item>;

    fn into_split_iter(self) -> Self::SplitIter;
}

impl<T: SplitIterator> IntoSplitIterator for T {
    type Item = <Self as SplitIterator>::Item;
    type SplitIter = Self;

    fn into_split_iter(self) -> Self::SplitIter {
        self
    }
}

impl<'a, T: 'a + Sync> IntoSplitIterator for &'a [T] {
    type Item = &'a T;
    type SplitIter = SliceSplit<'a, T>;

    fn into_split_iter(self) -> Self::SplitIter {
        SliceSplit(self)
    }
}

impl<'a, T: 'a + Sync + Send> IntoSplitIterator for &'a mut [T] {
    type Item = &'a mut T;
    type SplitIter = SliceSplitMut<'a, T>;

    fn into_split_iter(self) -> Self::SplitIter {
        SliceSplitMut(self)
    }
}

impl<'a, T: 'a + Sync> IntoSplitIterator for &'a Vec<T> {
    type Item = &'a T;
    type SplitIter = SliceSplit<'a, T>;

    fn into_split_iter(self) -> Self::SplitIter {
        SliceSplit(&self)
    }
}

impl<'a, T: 'a + Sync + Send> IntoSplitIterator for &'a mut Vec<T> {
    type Item = &'a mut T;
    type SplitIter = SliceSplitMut<'a, T>;

    fn into_split_iter(self) -> Self::SplitIter {
        SliceSplitMut(self)
    }
}

/// Used to mask data so that implementations don't conflict.
///
/// Specifically, this is used in the implementation of `SplitIterator`
/// for `Zip`, by hiding the base. This is because `SplitIterator` requires
/// that the base be `Split`. However, for `Split` types, there is a blanket
/// impl for `SplitIterator` for convenience, so if we didn't mask the type,
/// there would be conflicting implementations of `SplitIterator` for `Zip`.
/// This will be obsoleted when specialization becomes stable.
pub struct Hide<T>(T);

/// A split iterator over an immutable slice.
pub struct SliceSplit<'a, T: 'a>(&'a [T]);

/// A split iterator over a mutable slice.
pub struct SliceSplitMut<'a, T: 'a>(&'a mut [T]);

impl<'a, T: 'a> IntoIterator for SliceSplit<'a, T> {
    type Item = <&'a [T] as IntoIterator>::Item;
    type IntoIter = <&'a [T] as IntoIterator>::IntoIter;

    fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
}

impl<'a, T: 'a> IntoIterator for SliceSplitMut<'a, T> {
    type Item = <&'a mut [T] as IntoIterator>::Item;
    type IntoIter = <&'a mut [T] as IntoIterator>::IntoIter;

    fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
}

impl<'a, T: 'a + Sync> Split for SliceSplit<'a, T> {
    fn should_split(&self, mul: f32) -> Option<usize> {
        let len = self.0.len();
        if (len as f32 *mul) > 4096.0 { Some(len / 2) }
        else { None }
    }

    fn split(self, idx: usize) -> (Self, Self) {
        let (a, b) = self.0.split_at(idx);
        (
            SliceSplit(a),
            SliceSplit(b),
        )
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.0.len();

        (len, Some(len))
    }
}

impl<'a, T: 'a + Sync + Send> Split for SliceSplitMut<'a, T> {
    fn should_split(&self, mul: f32) -> Option<usize> {
        let len = self.0.len();
        if (len as f32 * mul) > 4096.0 { Some(len / 2) }
        else { None }
    }

    fn split(self, idx: usize) -> (Self, Self) {
        let (a, b) = self.0.split_at_mut(idx);
        (
            SliceSplitMut(a),
            SliceSplitMut(b),
        )
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.0.len();

        (len, Some(len))
    }
}

impl<'a, T: 'a + Sync> ExactSizeSplitIterator for SliceSplit<'a, T> {
    fn size(&self) -> usize {
        self.0.len()
    }
}

impl<'a, T: 'a + Sync + Send> ExactSizeSplitIterator for SliceSplitMut<'a, T> {
    fn size(&self) -> usize {
        self.0.len()
    }
}

pub trait Callback<T>: Sized {
    type Out;

    fn call<I: Iterator<Item=T>>(self, I) -> Self::Out;
}

impl<F, T> Callback<T> for F where F: FnMut(T) {
    type Out = ();

    fn call<I: Iterator<Item=T>>(mut self, iter: I) {
        for i in iter {
            (self)(i)
        }
    }
}

pub trait Consumer<In: IntoIterator>: Sync {
    type Item;

    /// Consume the iterator, typically by passing it on to the
    /// parent consumer along with a callback which will receive
    /// a producer of items to transform.
    fn consume<C: Callback<Self::Item>>(&self, i: In, cb: C) -> C::Out;
}

impl<In: IntoIterator> Consumer<In> for () {
    type Item = In::Item;

    fn consume<C: Callback<Self::Item>>(&self, i: In, cb: C) -> C::Out {
        cb.call(i.into_iter())
    }
}

#[cfg(test)]
mod tests {
    use ::{pool_harness, IntoSplitIterator, SplitIterator};

    #[test]
    fn doubling() {
        let v: Vec<_> = (0..5000).collect();

        pool_harness(|pool| {
            let mut v1 = v.clone();
            (&mut v1).into_split_iter().for_each(&pool.spawner(), |x| *x *= 2);

            assert_eq!(v1, (0..5000).map(|x| x * 2).collect::<Vec<_>>());
        });
    }
}<commit_msg>rewrite for_each to be more clean<commit_after>//! Parallel iterators.

use std::iter::FromIterator;

use super::Spawner;

mod collect;
mod enumerate;
mod filter;
mod map;
mod zip;

pub use self::collect::Combine;

/// A parallel iterator which works by splitting the underlying data
/// and sharing it between threads.
///
/// Functions which consume the iterator will take a `&Spawner` as an argument,
/// so that they can distribute their work in parallel.
pub trait SplitIterator: Sized {
    /// The item this iterator produces.
    type Item;

    /// The splittable base data which this consists of.
    type Base: Split;

    /// A consumer which can act as an ad-hoc iterator adapter
    /// chain while being shared across threads.
    type Consumer: Consumer<Self::Base, Item=Self::Item>;

    /// Destructure this iterator into a splittable base and
    /// a shareable consumer of that base.
    fn destructure(self) -> (Self::Base, Self::Consumer);

    /// Enumerate items by their index.
    fn enumerate(self) -> Enumerate<Self> {
        Enumerate {
            parent: self,
            off: 0,
        }
    }

    /// Filter items by some predicate.
    fn filter<F: Sync>(self, pred: F) -> Filter<Self, F> where F: Fn(&Self::Item) -> bool {
        Filter {
            parent: self,
            pred: pred,
        }
    }

    /// Map the items of this iterator to another type using the supplied function.
    fn map<F: Sync, U>(self, map: F) -> Map<Self, F> where F: Fn(Self::Item) -> U {
        Map {
            parent: self,
            map: map,
        }
    }

    /// Zip this iterator with another, combining their items
    /// in a tuple.
    fn zip<B: IntoSplitIterator>(self, other: B) -> Zip<Self, B::SplitIter> {
        Zip {
            a: self,
            b: other.into_split_iter(),
        }
    }

    /// Consume this iterator, performing an action for each item.
    fn for_each<F>(self, spawner: &Spawner, f: F) where F: Sync + Fn(Self::Item) {
        let (base, consumer) = self.destructure();
        for_each_helper::<Self, F>(base, &consumer, spawner, &f);
    }

    /// Collect the items of this iterator into a combinable collection.
    ///
    /// Note that this works by repeatedly combining the results of `from_iter`,
    /// so this will probably lead to more allocations than a single-threaded
    /// iterator `collect`.
    fn collect<T: Send>(self, spawner: &Spawner) -> T
    where Self::Item: Send, T: FromIterator<Self::Item> + Combine + Send {
        collect::collect(self, spawner)
    }

    /// A lower and optional upper bound on the size of this iterator.
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, None)
    }
}

fn for_each_helper<T, F>(base: T::Base, consumer: &T::Consumer, spawner: &Spawner, f: &F)
where T: SplitIterator, F: Sync + Fn(T::Item) {
    if let Some(idx) = base.should_split(1.0) {
        let (b1, b2) = base.split(idx);
        spawner.join(
            move |inner| for_each_helper::<T, F>(b1, consumer, inner, f),
            move |inner| for_each_helper::<T, F>(b2, consumer, inner, f),
        );
    } else {
        consumer.consume(base, f);
    }
}

/// An iterator for which the exact number of elements is known.
///
/// If this is implemented for an iterator,`size_hint` for that iterator
/// must return a pair of the exact size.
pub trait ExactSizeSplitIterator: SplitIterator {
    /// Get the number of elements in this iterator.
    fn size(&self) -> usize;
}

/// Enumerate iterator adapter
pub struct Enumerate<T> {
    parent: T,
    off: usize,
}

/// Filter ilterator adapter.
///
/// This filters each element by a given predicate.
pub struct Filter<T, F> {
    parent: T,
    pred: F,
}

/// Map iterator adapter.
///
/// This transforms each element into a new object.
pub struct Map<T, F> {
    parent: T,
    map: F,
}

/// Zip iterator adapter.
///
/// This combines two other iterators into one.
pub struct Zip<A, B> {
    a: A,
    b: B,
}

/// Data which can be split in two at an index.
pub trait Split: Send + IntoIterator {
    /// Whether this should split.
    ///
    /// This is given a multiplier, which tells you to treat the data
    /// as "mul" times as large as it is. The reason for this is that
    /// each iterator adapter makes producing an individual item more expensive.
    /// As the cost of producing each item goes up, we want to split the data
    /// into more parallelizable jobs so we can get better work distribution
    /// across threads.
    ///
    /// For example, should_split(1.0) for slices returns Some only
    /// when then length of the slice is over 4096. This means
    /// that `should_split(2.0)` will return Some when the length
    /// of the slice is over 2048.
    fn should_split(&self, mul: f32) -> Option<usize>;

    /// Split the data at the specified index.
    /// Note that this may not always be the same as the index
    /// you return from should_split.
    fn split(self, usize) -> (Self, Self);

    /// A hint for the size of this data, containing
    /// a known lower bound (potentially zero) and an optional upper bound.
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, None)
    }
}

impl<T: Split> SplitIterator for T {
    type Item = T::Item;
    type Base = Self;
    type Consumer = ();

    fn destructure(self) -> (Self, ()) {
        (self, ())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        Split::size_hint(self)
    }
}

/// Things that can be turned into a `SplitIterator`.
pub trait IntoSplitIterator {
    /// The item the split iterator will produce.
    type Item;

    /// The iterator this will turn into.
    type SplitIter: SplitIterator<Item=Self::Item>;

    fn into_split_iter(self) -> Self::SplitIter;
}

impl<T: SplitIterator> IntoSplitIterator for T {
    type Item = <Self as SplitIterator>::Item;
    type SplitIter = Self;

    fn into_split_iter(self) -> Self::SplitIter {
        self
    }
}

impl<'a, T: 'a + Sync> IntoSplitIterator for &'a [T] {
    type Item = &'a T;
    type SplitIter = SliceSplit<'a, T>;

    fn into_split_iter(self) -> Self::SplitIter {
        SliceSplit(self)
    }
}

impl<'a, T: 'a + Sync + Send> IntoSplitIterator for &'a mut [T] {
    type Item = &'a mut T;
    type SplitIter = SliceSplitMut<'a, T>;

    fn into_split_iter(self) -> Self::SplitIter {
        SliceSplitMut(self)
    }
}

impl<'a, T: 'a + Sync> IntoSplitIterator for &'a Vec<T> {
    type Item = &'a T;
    type SplitIter = SliceSplit<'a, T>;

    fn into_split_iter(self) -> Self::SplitIter {
        SliceSplit(&self)
    }
}

impl<'a, T: 'a + Sync + Send> IntoSplitIterator for &'a mut Vec<T> {
    type Item = &'a mut T;
    type SplitIter = SliceSplitMut<'a, T>;

    fn into_split_iter(self) -> Self::SplitIter {
        SliceSplitMut(self)
    }
}

/// Used to mask data so that implementations don't conflict.
///
/// Specifically, this is used in the implementation of `SplitIterator`
/// for `Zip`, by hiding the base. This is because `SplitIterator` requires
/// that the base be `Split`. However, for `Split` types, there is a blanket
/// impl for `SplitIterator` for convenience, so if we didn't mask the type,
/// there would be conflicting implementations of `SplitIterator` for `Zip`.
/// This will be obsoleted when specialization becomes stable.
pub struct Hide<T>(T);

/// A split iterator over an immutable slice.
pub struct SliceSplit<'a, T: 'a>(&'a [T]);

/// A split iterator over a mutable slice.
pub struct SliceSplitMut<'a, T: 'a>(&'a mut [T]);

impl<'a, T: 'a> IntoIterator for SliceSplit<'a, T> {
    type Item = <&'a [T] as IntoIterator>::Item;
    type IntoIter = <&'a [T] as IntoIterator>::IntoIter;

    fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
}

impl<'a, T: 'a> IntoIterator for SliceSplitMut<'a, T> {
    type Item = <&'a mut [T] as IntoIterator>::Item;
    type IntoIter = <&'a mut [T] as IntoIterator>::IntoIter;

    fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
}

impl<'a, T: 'a + Sync> Split for SliceSplit<'a, T> {
    fn should_split(&self, mul: f32) -> Option<usize> {
        let len = self.0.len();
        if (len as f32 *mul) > 4096.0 { Some(len / 2) }
        else { None }
    }

    fn split(self, idx: usize) -> (Self, Self) {
        let (a, b) = self.0.split_at(idx);
        (
            SliceSplit(a),
            SliceSplit(b),
        )
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.0.len();

        (len, Some(len))
    }
}

impl<'a, T: 'a + Sync + Send> Split for SliceSplitMut<'a, T> {
    fn should_split(&self, mul: f32) -> Option<usize> {
        let len = self.0.len();
        if (len as f32 * mul) > 4096.0 { Some(len / 2) }
        else { None }
    }

    fn split(self, idx: usize) -> (Self, Self) {
        let (a, b) = self.0.split_at_mut(idx);
        (
            SliceSplitMut(a),
            SliceSplitMut(b),
        )
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.0.len();

        (len, Some(len))
    }
}

impl<'a, T: 'a + Sync> ExactSizeSplitIterator for SliceSplit<'a, T> {
    fn size(&self) -> usize {
        self.0.len()
    }
}

impl<'a, T: 'a + Sync + Send> ExactSizeSplitIterator for SliceSplitMut<'a, T> {
    fn size(&self) -> usize {
        self.0.len()
    }
}

pub trait Callback<T>: Sized {
    type Out;

    fn call<I: Iterator<Item=T>>(self, I) -> Self::Out;
}

impl<F, T> Callback<T> for F where F: FnMut(T) {
    type Out = ();

    fn call<I: Iterator<Item=T>>(mut self, iter: I) {
        for i in iter {
            (self)(i)
        }
    }
}

pub trait Consumer<In: IntoIterator>: Sync {
    type Item;

    /// Consume the iterator, typically by passing it on to the
    /// parent consumer along with a callback which will receive
    /// a producer of items to transform.
    fn consume<C: Callback<Self::Item>>(&self, i: In, cb: C) -> C::Out;
}

impl<In: IntoIterator> Consumer<In> for () {
    type Item = In::Item;

    fn consume<C: Callback<Self::Item>>(&self, i: In, cb: C) -> C::Out {
        cb.call(i.into_iter())
    }
}

#[cfg(test)]
mod tests {
    use ::{pool_harness, IntoSplitIterator, SplitIterator};

    #[test]
    fn doubling() {
        let v: Vec<_> = (0..5000).collect();

        pool_harness(|pool| {
            let mut v1 = v.clone();
            (&mut v1).into_split_iter().for_each(&pool.spawner(), |x| *x *= 2);

            assert_eq!(v1, (0..5000).map(|x| x * 2).collect::<Vec<_>>());
        });
    }
}<|endoftext|>


<commit_before>extern crate indyrs as indy;
extern crate indyrs as api;

use std::sync::Mutex;

use indy::future::Future;
use indy_api_types::PoolHandle;
use log::{LevelFilter, Log, Metadata, Record};

#[macro_use]
mod utils;

inject_indy_dependencies!();

struct LogCounter {}

static LOG_COUNTER: LogCounter = LogCounter {};

lazy_static! {
    static ref LOG_STAT: Mutex<[usize; 6]> = Mutex::new([0usize; 6]);
    static ref LOG_IGNORE_IN_STAT: Mutex<Vec<&'static str>> = Mutex::new(Vec::new());
}

impl Log for LogCounter {
    fn enabled(&self, _metadata: &Metadata) -> bool {
        true
    }

    fn log(&self, record: &Record) {
        if !LOG_IGNORE_IN_STAT.lock().unwrap().contains(&record.target()) {
            LOG_STAT.lock().unwrap()[record.metadata().level() as usize] += 1;
        }
    }

    fn flush(&self) {}
}

#[test]
fn indy_set_log_max_lvl_works() {
    indy::logger::set_logger(&LOG_COUNTER).unwrap();
    LOG_IGNORE_IN_STAT.lock().unwrap().push("indy::api::logger");

    indy::pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err();
    let log_stat_default = LOG_STAT.lock().unwrap().clone();

    indy::pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err();
    let log_stat_default_2 = LOG_STAT.lock().unwrap().clone();

    unsafe { indy_sys::logger::indy_set_log_max_lvl(LevelFilter::Off as usize as u32); }
    indy::pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err();
    let log_stat_off = LOG_STAT.lock().unwrap().clone();

    unsafe { indy_sys::logger::indy_set_log_max_lvl(LevelFilter::max() as usize as u32); }
    indy::pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err();
    let log_stat_all = LOG_STAT.lock().unwrap().clone();

    unsafe { indy_sys::logger::indy_set_log_max_lvl(LevelFilter::Debug as usize as u32); }
    indy::pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err();
    let log_stat_no_trace = LOG_STAT.lock().unwrap().clone();

    // make sure pool close operation triggers some logging
    assert_ne!(log_stat_default[LevelFilter::Debug as usize], log_stat_default_2[LevelFilter::Debug as usize]);
    assert_ne!(log_stat_default[LevelFilter::Trace as usize], log_stat_default_2[LevelFilter::Trace as usize]);

    // check logging off results
    assert_eq!(log_stat_default_2[LevelFilter::Debug as usize], log_stat_off[LevelFilter::Debug as usize]);
    assert_eq!(log_stat_default_2[LevelFilter::Trace as usize], log_stat_off[LevelFilter::Trace as usize]);

    // check re-enabled logs
    assert_ne!(log_stat_off[LevelFilter::Debug as usize], log_stat_all[LevelFilter::Debug as usize]);
    assert_ne!(log_stat_off[LevelFilter::Trace as usize], log_stat_all[LevelFilter::Trace as usize]);

    // check disabled trace
    assert_ne!(log_stat_all[LevelFilter::Debug as usize], log_stat_no_trace[LevelFilter::Debug as usize]);
    assert_eq!(log_stat_all[LevelFilter::Trace as usize], log_stat_no_trace[LevelFilter::Trace as usize]);
}
<commit_msg>Fix indy_set_log_max_lvl_works in release mode.<commit_after>extern crate indyrs as indy;
extern crate indyrs as api;

use std::sync::Mutex;

use indy::future::Future;
use indy_api_types::PoolHandle;
use log::{LevelFilter, Log, Metadata, Record};

#[macro_use]
mod utils;

inject_indy_dependencies!();

struct LogCounter {}

static LOG_COUNTER: LogCounter = LogCounter {};

lazy_static! {
    static ref LOG_STAT: Mutex<[usize; 6]> = Mutex::new([0usize; 6]);
    static ref LOG_IGNORE_IN_STAT: Mutex<Vec<&'static str>> = Mutex::new(Vec::new());
}

impl Log for LogCounter {
    fn enabled(&self, _metadata: &Metadata) -> bool {
        true
    }

    fn log(&self, record: &Record) {
        if !LOG_IGNORE_IN_STAT.lock().unwrap().contains(&record.target()) {
            LOG_STAT.lock().unwrap()[record.metadata().level() as usize] += 1;
        }
    }

    fn flush(&self) {}
}

#[test]
fn indy_set_log_max_lvl_works() {
    indy::logger::set_logger(&LOG_COUNTER).unwrap();
    unsafe { indy_sys::logger::indy_set_log_max_lvl(LevelFilter::Trace as usize as u32); }
    LOG_IGNORE_IN_STAT.lock().unwrap().push("indy::api::logger");

    indy::pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err();
    let log_stat_default = LOG_STAT.lock().unwrap().clone();

    indy::pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err();
    let log_stat_default_2 = LOG_STAT.lock().unwrap().clone();

    unsafe { indy_sys::logger::indy_set_log_max_lvl(LevelFilter::Off as usize as u32); }
    indy::pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err();
    let log_stat_off = LOG_STAT.lock().unwrap().clone();

    unsafe { indy_sys::logger::indy_set_log_max_lvl(LevelFilter::max() as usize as u32); }
    indy::pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err();
    let log_stat_all = LOG_STAT.lock().unwrap().clone();

    unsafe { indy_sys::logger::indy_set_log_max_lvl(LevelFilter::Debug as usize as u32); }
    indy::pool::close_pool_ledger(1 as PoolHandle).wait().unwrap_err();
    let log_stat_no_trace = LOG_STAT.lock().unwrap().clone();

    // make sure pool close operation triggers some logging
    assert_ne!(log_stat_default[LevelFilter::Debug as usize], log_stat_default_2[LevelFilter::Debug as usize]);
    assert_ne!(log_stat_default[LevelFilter::Trace as usize], log_stat_default_2[LevelFilter::Trace as usize]);

    // check logging off results
    assert_eq!(log_stat_default_2[LevelFilter::Debug as usize], log_stat_off[LevelFilter::Debug as usize]);
    assert_eq!(log_stat_default_2[LevelFilter::Trace as usize], log_stat_off[LevelFilter::Trace as usize]);

    // check re-enabled logs
    assert_ne!(log_stat_off[LevelFilter::Debug as usize], log_stat_all[LevelFilter::Debug as usize]);
    assert_ne!(log_stat_off[LevelFilter::Trace as usize], log_stat_all[LevelFilter::Trace as usize]);

    // check disabled trace
    assert_ne!(log_stat_all[LevelFilter::Debug as usize], log_stat_no_trace[LevelFilter::Debug as usize]);
    assert_eq!(log_stat_all[LevelFilter::Trace as usize], log_stat_no_trace[LevelFilter::Trace as usize]);
}
<|endoftext|>


<commit_before>
<commit_msg>Add unit tests for net::ip<commit_after>use super::*;

use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};

#[test]
fn ip_correct() {
    let ip = ip("8.8.8.8:80");
    let correct = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(8, 8, 8, 8), 80));
    assert_eq!(ip, correct);
}

#[test]
#[should_panic(expected = "because localhost can resolve to both 127.0.0.1, and the various IPV6 versions \
        of 127.0.0.1, it may not be used. please instead use 127.0.0.1")]
fn ip_localhost() {
    ip("localhost:80");
}
<|endoftext|>