<commit_before>use std::collections::HashMap;

use crate::controllers::frontend_prelude::*;

use crate::controllers::helpers::*;
use crate::email;

use crate::models::{
    CrateOwner, Email, Follow, NewEmail, OwnerKind, User, Version, VersionOwnerAction,
};
use crate::schema::{crate_owners, crates, emails, follows, users, versions};
use crate::views::{EncodableMe, EncodableVersion, OwnedCrate};

/// Handles the `GET /me` route.
pub fn me(req: &mut dyn RequestExt) -> EndpointResult {
    let user_id = req.authenticate()?.user_id();
    let conn = req.db_conn()?;

    let (user, verified, email, verification_sent) = users::table
        .find(user_id)
        .left_join(emails::table)
        .select((
            users::all_columns,
            emails::verified.nullable(),
            emails::email.nullable(),
            emails::token_generated_at.nullable().is_not_null(),
        ))
        .first::<(User, Option<bool>, Option<String>, bool)>(&*conn)?;

    let owned_crates = CrateOwner::by_owner_kind(OwnerKind::User)
        .inner_join(crates::table)
        .filter(crate_owners::owner_id.eq(user_id))
        .select((crates::id, crates::name, crate_owners::email_notifications))
        .order(crates::name.asc())
        .load(&*conn)?
        .into_iter()
        .map(|(id, name, email_notifications)| OwnedCrate {
            id,
            name,
            email_notifications,
        })
        .collect();

    let verified = verified.unwrap_or(false);
    let verification_sent = verified || verification_sent;
    Ok(req.json(&EncodableMe {
        user: user.encodable_private(email, verified, verification_sent),
        owned_crates,
    }))
}

/// Handles the `GET /me/updates` route.
pub fn updates(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::dsl::any;

    let authenticated_user = req.authenticate()?;
    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    let followed_crates = Follow::belonging_to(&user).select(follows::crate_id);
    let data = versions::table
        .inner_join(crates::table)
        .left_outer_join(users::table)
        .filter(crates::id.eq(any(followed_crates)))
        .order(versions::created_at.desc())
        .select((
            versions::all_columns,
            crates::name,
            users::all_columns.nullable(),
        ))
        .paginate(&req.query())?
        .load::<(Version, String, Option<User>)>(&*conn)?;
    let more = data.next_page_params().is_some();
    let versions = data.iter().map(|(v, _, _)| v).cloned().collect::<Vec<_>>();
    let data = data
        .into_iter()
        .zip(VersionOwnerAction::for_versions(&conn, &versions)?.into_iter())
        .map(|((v, cn, pb), voas)| (v, cn, pb, voas))
        .collect::<Vec<_>>();

    let versions = data
        .into_iter()
        .map(|(version, crate_name, published_by, actions)| {
            version.encodable(&crate_name, published_by, actions)
        })
        .collect();

    #[derive(Serialize)]
    struct R {
        versions: Vec<EncodableVersion>,
        meta: Meta,
    }
    #[derive(Serialize)]
    struct Meta {
        more: bool,
    }
    Ok(req.json(&R {
        versions,
        meta: Meta { more },
    }))
}

/// Handles the `PUT /user/:user_id` route.
pub fn update_user(req: &mut dyn RequestExt) -> EndpointResult {
    use self::emails::user_id;
    use diesel::insert_into;

    let authenticated_user = req.authenticate()?;

    let mut body = String::new();
    req.body().read_to_string(&mut body)?;

    let param_user_id = &req.params()["user_id"];
    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    // need to check if current user matches user to be updated
    if &user.id.to_string() != param_user_id {
        return Err(bad_request("current user does not match requested user"));
    }

    #[derive(Deserialize)]
    struct UserUpdate {
        user: User,
    }

    #[derive(Deserialize)]
    struct User {
        email: Option<String>,
    }

    let user_update: UserUpdate =
        serde_json::from_str(&body).map_err(|_| bad_request("invalid json request"))?;

    let user_email = match &user_update.user.email {
        Some(email) => email.trim(),
        None => return Err(bad_request("empty email rejected")),
    };

    if user_email == "" {
        return Err(bad_request("empty email rejected"));
    }

    conn.transaction::<_, Box<dyn AppError>, _>(|| {
        let new_email = NewEmail {
            user_id: user.id,
            email: user_email,
        };

        let token = insert_into(emails::table)
            .values(&new_email)
            .on_conflict(user_id)
            .do_update()
            .set(&new_email)
            .returning(emails::token)
            .get_result::<String>(&*conn)
            .map_err(|_| server_error("Error in creating token"))?;

        crate::email::send_user_confirm_email(user_email, &user.gh_login, &token);

        Ok(())
    })?;

    ok_true()
}

/// Handles the `PUT /confirm/:email_token` route
pub fn confirm_user_email(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::update;

    let conn = req.db_conn()?;
    let req_token = &req.params()["email_token"];

    let updated_rows = update(emails::table.filter(emails::token.eq(req_token)))
        .set(emails::verified.eq(true))
        .execute(&*conn)?;

    if updated_rows == 0 {
        return Err(bad_request("Email belonging to token not found."));
    }

    ok_true()
}

/// Handles `PUT /user/:user_id/resend` route
pub fn regenerate_token_and_send(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::dsl::sql;
    use diesel::update;

    let param_user_id = req.params()["user_id"]
        .parse::<i32>()
        .chain_error(|| bad_request("invalid user_id"))?;
    let authenticated_user = req.authenticate()?;
    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    // need to check if current user matches user to be updated
    if user.id != param_user_id {
        return Err(bad_request("current user does not match requested user"));
    }

    conn.transaction(|| {
        let email = update(Email::belonging_to(&user))
            .set(emails::token.eq(sql("DEFAULT")))
            .get_result::<Email>(&*conn)
            .map_err(|_| bad_request("Email could not be found"))?;

        email::try_send_user_confirm_email(&email.email, &user.gh_login, &email.token)
            .map_err(|_| server_error("Error in sending email"))
    })?;

    ok_true()
}

/// Handles `PUT /me/email_notifications` route
pub fn update_email_notifications(req: &mut dyn RequestExt) -> EndpointResult {
    use self::crate_owners::dsl::*;
    use diesel::pg::upsert::excluded;

    #[derive(Deserialize)]
    struct CrateEmailNotifications {
        id: i32,
        email_notifications: bool,
    }

    let mut body = String::new();
    req.body().read_to_string(&mut body)?;
    let updates: HashMap<i32, bool> = serde_json::from_str::<Vec<CrateEmailNotifications>>(&body)
        .map_err(|_| bad_request("invalid json request"))?
        .iter()
        .map(|c| (c.id, c.email_notifications))
        .collect();

    let user_id = req.authenticate()?.user_id();
    let conn = req.db_conn()?;

    // Build inserts from existing crates belonging to the current user
    let to_insert = CrateOwner::by_owner_kind(OwnerKind::User)
        .filter(owner_id.eq(user_id))
        .select((crate_id, owner_id, owner_kind, email_notifications))
        .load(&*conn)?
        .into_iter()
        // Remove records whose `email_notifications` will not change from their current value
        .map(
            |(c_id, o_id, o_kind, e_notifications): (i32, i32, i32, bool)| {
                let current_e_notifications = *updates.get(&c_id).unwrap_or(&e_notifications);
                (
                    crate_id.eq(c_id),
                    owner_id.eq(o_id),
                    owner_kind.eq(o_kind),
                    email_notifications.eq(current_e_notifications),
                )
            },
        )
        .collect::<Vec<_>>();

    // Upsert crate owners; this should only actually exectute updates
    diesel::insert_into(crate_owners)
        .values(&to_insert)
        .on_conflict((crate_id, owner_id, owner_kind))
        .do_update()
        .set(email_notifications.eq(excluded(email_notifications)))
        .execute(&*conn)?;

    ok_true()
}
<commit_msg>Auto merge of #2856 - Turbo87:typo, r=jtgeibel<commit_after>use std::collections::HashMap;

use crate::controllers::frontend_prelude::*;

use crate::controllers::helpers::*;
use crate::email;

use crate::models::{
    CrateOwner, Email, Follow, NewEmail, OwnerKind, User, Version, VersionOwnerAction,
};
use crate::schema::{crate_owners, crates, emails, follows, users, versions};
use crate::views::{EncodableMe, EncodableVersion, OwnedCrate};

/// Handles the `GET /me` route.
pub fn me(req: &mut dyn RequestExt) -> EndpointResult {
    let user_id = req.authenticate()?.user_id();
    let conn = req.db_conn()?;

    let (user, verified, email, verification_sent) = users::table
        .find(user_id)
        .left_join(emails::table)
        .select((
            users::all_columns,
            emails::verified.nullable(),
            emails::email.nullable(),
            emails::token_generated_at.nullable().is_not_null(),
        ))
        .first::<(User, Option<bool>, Option<String>, bool)>(&*conn)?;

    let owned_crates = CrateOwner::by_owner_kind(OwnerKind::User)
        .inner_join(crates::table)
        .filter(crate_owners::owner_id.eq(user_id))
        .select((crates::id, crates::name, crate_owners::email_notifications))
        .order(crates::name.asc())
        .load(&*conn)?
        .into_iter()
        .map(|(id, name, email_notifications)| OwnedCrate {
            id,
            name,
            email_notifications,
        })
        .collect();

    let verified = verified.unwrap_or(false);
    let verification_sent = verified || verification_sent;
    Ok(req.json(&EncodableMe {
        user: user.encodable_private(email, verified, verification_sent),
        owned_crates,
    }))
}

/// Handles the `GET /me/updates` route.
pub fn updates(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::dsl::any;

    let authenticated_user = req.authenticate()?;
    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    let followed_crates = Follow::belonging_to(&user).select(follows::crate_id);
    let data = versions::table
        .inner_join(crates::table)
        .left_outer_join(users::table)
        .filter(crates::id.eq(any(followed_crates)))
        .order(versions::created_at.desc())
        .select((
            versions::all_columns,
            crates::name,
            users::all_columns.nullable(),
        ))
        .paginate(&req.query())?
        .load::<(Version, String, Option<User>)>(&*conn)?;
    let more = data.next_page_params().is_some();
    let versions = data.iter().map(|(v, _, _)| v).cloned().collect::<Vec<_>>();
    let data = data
        .into_iter()
        .zip(VersionOwnerAction::for_versions(&conn, &versions)?.into_iter())
        .map(|((v, cn, pb), voas)| (v, cn, pb, voas))
        .collect::<Vec<_>>();

    let versions = data
        .into_iter()
        .map(|(version, crate_name, published_by, actions)| {
            version.encodable(&crate_name, published_by, actions)
        })
        .collect();

    #[derive(Serialize)]
    struct R {
        versions: Vec<EncodableVersion>,
        meta: Meta,
    }
    #[derive(Serialize)]
    struct Meta {
        more: bool,
    }
    Ok(req.json(&R {
        versions,
        meta: Meta { more },
    }))
}

/// Handles the `PUT /users/:user_id` route.
pub fn update_user(req: &mut dyn RequestExt) -> EndpointResult {
    use self::emails::user_id;
    use diesel::insert_into;

    let authenticated_user = req.authenticate()?;

    let mut body = String::new();
    req.body().read_to_string(&mut body)?;

    let param_user_id = &req.params()["user_id"];
    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    // need to check if current user matches user to be updated
    if &user.id.to_string() != param_user_id {
        return Err(bad_request("current user does not match requested user"));
    }

    #[derive(Deserialize)]
    struct UserUpdate {
        user: User,
    }

    #[derive(Deserialize)]
    struct User {
        email: Option<String>,
    }

    let user_update: UserUpdate =
        serde_json::from_str(&body).map_err(|_| bad_request("invalid json request"))?;

    let user_email = match &user_update.user.email {
        Some(email) => email.trim(),
        None => return Err(bad_request("empty email rejected")),
    };

    if user_email == "" {
        return Err(bad_request("empty email rejected"));
    }

    conn.transaction::<_, Box<dyn AppError>, _>(|| {
        let new_email = NewEmail {
            user_id: user.id,
            email: user_email,
        };

        let token = insert_into(emails::table)
            .values(&new_email)
            .on_conflict(user_id)
            .do_update()
            .set(&new_email)
            .returning(emails::token)
            .get_result::<String>(&*conn)
            .map_err(|_| server_error("Error in creating token"))?;

        crate::email::send_user_confirm_email(user_email, &user.gh_login, &token);

        Ok(())
    })?;

    ok_true()
}

/// Handles the `PUT /confirm/:email_token` route
pub fn confirm_user_email(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::update;

    let conn = req.db_conn()?;
    let req_token = &req.params()["email_token"];

    let updated_rows = update(emails::table.filter(emails::token.eq(req_token)))
        .set(emails::verified.eq(true))
        .execute(&*conn)?;

    if updated_rows == 0 {
        return Err(bad_request("Email belonging to token not found."));
    }

    ok_true()
}

/// Handles `PUT /user/:user_id/resend` route
pub fn regenerate_token_and_send(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::dsl::sql;
    use diesel::update;

    let param_user_id = req.params()["user_id"]
        .parse::<i32>()
        .chain_error(|| bad_request("invalid user_id"))?;
    let authenticated_user = req.authenticate()?;
    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    // need to check if current user matches user to be updated
    if user.id != param_user_id {
        return Err(bad_request("current user does not match requested user"));
    }

    conn.transaction(|| {
        let email = update(Email::belonging_to(&user))
            .set(emails::token.eq(sql("DEFAULT")))
            .get_result::<Email>(&*conn)
            .map_err(|_| bad_request("Email could not be found"))?;

        email::try_send_user_confirm_email(&email.email, &user.gh_login, &email.token)
            .map_err(|_| server_error("Error in sending email"))
    })?;

    ok_true()
}

/// Handles `PUT /me/email_notifications` route
pub fn update_email_notifications(req: &mut dyn RequestExt) -> EndpointResult {
    use self::crate_owners::dsl::*;
    use diesel::pg::upsert::excluded;

    #[derive(Deserialize)]
    struct CrateEmailNotifications {
        id: i32,
        email_notifications: bool,
    }

    let mut body = String::new();
    req.body().read_to_string(&mut body)?;
    let updates: HashMap<i32, bool> = serde_json::from_str::<Vec<CrateEmailNotifications>>(&body)
        .map_err(|_| bad_request("invalid json request"))?
        .iter()
        .map(|c| (c.id, c.email_notifications))
        .collect();

    let user_id = req.authenticate()?.user_id();
    let conn = req.db_conn()?;

    // Build inserts from existing crates belonging to the current user
    let to_insert = CrateOwner::by_owner_kind(OwnerKind::User)
        .filter(owner_id.eq(user_id))
        .select((crate_id, owner_id, owner_kind, email_notifications))
        .load(&*conn)?
        .into_iter()
        // Remove records whose `email_notifications` will not change from their current value
        .map(
            |(c_id, o_id, o_kind, e_notifications): (i32, i32, i32, bool)| {
                let current_e_notifications = *updates.get(&c_id).unwrap_or(&e_notifications);
                (
                    crate_id.eq(c_id),
                    owner_id.eq(o_id),
                    owner_kind.eq(o_kind),
                    email_notifications.eq(current_e_notifications),
                )
            },
        )
        .collect::<Vec<_>>();

    // Upsert crate owners; this should only actually exectute updates
    diesel::insert_into(crate_owners)
        .values(&to_insert)
        .on_conflict((crate_id, owner_id, owner_kind))
        .do_update()
        .set(email_notifications.eq(excluded(email_notifications)))
        .execute(&*conn)?;

    ok_true()
}
<|endoftext|>


<commit_before>//! All keys in leveldb are compared by their binary value unless
//! defined otherwise.
//!
//! Comparators allow to override this comparison.
//! The ordering of keys introduced by the compartor influences iteration order.
//! Databases written with one Comparator cannot be opened with another.
use cbits::leveldb::*;
use libc::{size_t,c_void};
use libc;
use std::mem;
use std::slice;
use std::cmp::Ordering;
use database::db_key::Key;
use database::db_key::from_u8;

/// A comparator has two important functions:
///
/// * the name function returns a fixed name to detect errors when
///   opening databases with a different name
/// * The comparison implementation
pub trait Comparator<K: Key> {
     /// Return the name of the Comparator
     fn name(&self) -> *const u8;
     /// compare two keys. This must implement a total ordering.
     fn compare(&self, a: &K, b: &K) -> Ordering;
     /// whether the comparator is the `DefaultComparator`
     fn null() -> bool {
         false
     }
}

/// OrdComparator is a comparator comparing Keys that implement `Ord`
#[derive(Copy)]
pub struct OrdComparator;
/// DefaultComparator is the a stand in for "no comparator set"
#[derive(Copy)]
pub struct DefaultComparator;

extern "C" fn name<K: Key, T: Comparator<K>>(state: *mut libc::c_void) -> *const u8 {
     let x: &T = unsafe { &*(state as *mut T) };
     x.name()
}

extern "C" fn compare<K: Key, T: Comparator<K>>(state: *mut libc::c_void,
                                     a: *const u8, a_len: size_t,
                                     b: *const u8, b_len: size_t) -> i32 {
     unsafe {
          let a_slice = slice::from_raw_buf(&a, a_len as usize);
          let b_slice = slice::from_raw_buf(&b, b_len as usize);
          let x: &T = &*(state as *mut T);
          let a_key = from_u8::<K>(a_slice);
          let b_key = from_u8::<K>(b_slice);
          match x.compare(&a_key, &b_key) {
              Ordering::Less => -1,
              Ordering::Equal => 0,
              Ordering::Greater => 1
          }
     }
}

extern "C" fn destructor<T>(state: *mut libc::c_void) {
     let _x: Box<T> = unsafe {mem::transmute(state)};
     // let the Box fall out of scope and run the T's destructor
}

#[allow(missing_docs)]
pub fn create_comparator<K: Key, T: Comparator<K>>(x: Box<T>) -> *mut leveldb_comparator_t {
     unsafe {
          leveldb_comparator_create(mem::transmute(x),
                                    destructor::<T>,
                                    compare::<K, T>,
                                    name::<K, T>)
     }
}

impl<K: Key + Ord> Comparator<K> for OrdComparator {
  fn name(&self) -> *const u8 {
    "ord_comparator".as_ptr()
  }

  fn compare(&self, a: &K, b: &K) -> Ordering {
    a.cmp(b)
  }
}

impl<K: Key> Comparator<K> for DefaultComparator {
  fn name(&self) -> *const u8 {
    "default_comparator".as_ptr()
  }

  fn compare(&self, _a: &K, _b: &K) -> Ordering {
    Ordering::Equal
  }

  fn null() -> bool {
    true
  }
}
<commit_msg>Use from_raw_parts instead of from_raw_buf<commit_after>//! All keys in leveldb are compared by their binary value unless
//! defined otherwise.
//!
//! Comparators allow to override this comparison.
//! The ordering of keys introduced by the compartor influences iteration order.
//! Databases written with one Comparator cannot be opened with another.
use cbits::leveldb::*;
use libc::{size_t,c_void};
use libc;
use std::mem;
use std::slice;
use std::cmp::Ordering;
use database::db_key::Key;
use database::db_key::from_u8;

/// A comparator has two important functions:
///
/// * the name function returns a fixed name to detect errors when
///   opening databases with a different name
/// * The comparison implementation
pub trait Comparator<K: Key> {
     /// Return the name of the Comparator
     fn name(&self) -> *const u8;
     /// compare two keys. This must implement a total ordering.
     fn compare(&self, a: &K, b: &K) -> Ordering;
     /// whether the comparator is the `DefaultComparator`
     fn null() -> bool {
         false
     }
}

/// OrdComparator is a comparator comparing Keys that implement `Ord`
#[derive(Copy)]
pub struct OrdComparator;
/// DefaultComparator is the a stand in for "no comparator set"
#[derive(Copy)]
pub struct DefaultComparator;

extern "C" fn name<K: Key, T: Comparator<K>>(state: *mut libc::c_void) -> *const u8 {
     let x: &T = unsafe { &*(state as *mut T) };
     x.name()
}

extern "C" fn compare<K: Key, T: Comparator<K>>(state: *mut libc::c_void,
                                     a: *const u8, a_len: size_t,
                                     b: *const u8, b_len: size_t) -> i32 {
     unsafe {
          let a_slice = slice::from_raw_parts::<u8>(a, a_len as usize);
          let b_slice = slice::from_raw_parts::<u8>(b, b_len as usize);
          let x: &T = &*(state as *mut T);
          let a_key = from_u8::<K>(a_slice);
          let b_key = from_u8::<K>(b_slice);
          match x.compare(&a_key, &b_key) {
              Ordering::Less => -1,
              Ordering::Equal => 0,
              Ordering::Greater => 1
          }
     }
}

extern "C" fn destructor<T>(state: *mut libc::c_void) {
     let _x: Box<T> = unsafe {mem::transmute(state)};
     // let the Box fall out of scope and run the T's destructor
}

#[allow(missing_docs)]
pub fn create_comparator<K: Key, T: Comparator<K>>(x: Box<T>) -> *mut leveldb_comparator_t {
     unsafe {
          leveldb_comparator_create(mem::transmute(x),
                                    destructor::<T>,
                                    compare::<K, T>,
                                    name::<K, T>)
     }
}

impl<K: Key + Ord> Comparator<K> for OrdComparator {
  fn name(&self) -> *const u8 {
    "ord_comparator".as_ptr()
  }

  fn compare(&self, a: &K, b: &K) -> Ordering {
    a.cmp(b)
  }
}

impl<K: Key> Comparator<K> for DefaultComparator {
  fn name(&self) -> *const u8 {
    "default_comparator".as_ptr()
  }

  fn compare(&self, _a: &K, _b: &K) -> Ordering {
    Ordering::Equal
  }

  fn null() -> bool {
    true
  }
}
<|endoftext|>


<commit_before>use sys;
use bullet_vector3::BulletVector3;
use collision::collision_shapes::Shape;
use mint::{Vector3, Vector4};

pub struct RigidBody {
    rigid_body: Box<sys::btRigidBody>,
    shape: Box<Shape>,
    motion_state: Box<sys::btDefaultMotionState>,
    construction_info: Box<sys::btRigidBody_btRigidBodyConstructionInfo>,
}

impl RigidBody {
    pub fn new<T1: Into<Vector3<f64>>, T2: Into<Vector3<f64>>, T3: Into<Vector4<f64>>>(
        mass: f64,
        inertia: T1,
        shape: Shape,
        translation: T2,
        orientation: T3,
    ) -> RigidBody {
        let mut inertia: BulletVector3 = inertia.into().into();
        let shape_box = Box::new(shape);
        let translation: BulletVector3 = translation.into().into();
        let orientation: [f64; 4] = orientation.into().into();
        let transform = unsafe {
            sys::btTransform::new1(
                &orientation as *const _ as *const _,
                &translation as *const _ as *const _,
            )
        };
        let mut motion_state_box = Box::new(unsafe {
            sys::btDefaultMotionState::new(&transform as *const _, sys::btTransform::getIdentity())
        });

        let construction_info_box = Box::new(unsafe {
            sys::btRigidBody_btRigidBodyConstructionInfo::new(
                mass,
                &mut *motion_state_box as *mut _ as *mut _,
                shape_box.as_ptr(),
                inertia.0.as_mut_ptr() as *mut _,
            )
        });
        RigidBody {
            rigid_body: Box::new(unsafe {
                sys::btRigidBody::new(&*construction_info_box as *const _)
            }),
            shape: shape_box,
            motion_state: motion_state_box,
            construction_info: construction_info_box,
        }
    }

    pub(crate) unsafe fn motion_state_ptr(&self) -> *mut sys::btDefaultMotionState {
        &*self.motion_state as *const _ as *mut _
    }

    pub(crate) unsafe fn as_ptr(&self) -> *mut sys::btRigidBody {
        &*self.rigid_body as *const _ as *mut _
    }
}

#[derive(Clone)]
pub struct RigidBodyHandle {
    pub(in dynamics) ptr: *mut sys::btRigidBody,
    motion_state: *mut sys::btDefaultMotionState,
    temp_transform: sys::btTransform,
}

impl RigidBodyHandle {
    pub fn new(ptr: *mut sys::btRigidBody, motion_state: *mut sys::btDefaultMotionState) -> Self {
        let temp_transform = unsafe { sys::btTransform::new() };

        RigidBodyHandle {
            ptr,
            motion_state,
            temp_transform,
        }
    }
    pub fn set_restitution(&mut self, restitution: f64) {
        unsafe {
            sys::btCollisionObject_setRestitution(self.ptr as *mut _, restitution);
        }
    }
    pub fn set_friction(&mut self, friction: f64) {
        unsafe {
            sys::btCollisionObject_setFriction(self.ptr as *mut _, friction);
        }
    }
    pub fn set_gravity<T: Into<Vector3<f64>>>(&mut self, gravity: T) {
        let gravity: BulletVector3 = gravity.into().into();
        unsafe {
            sys::btRigidBody_setGravity(self.ptr, gravity.0.as_ptr() as *const _);
        }
    }

    pub fn set_angular_factor<T: Into<Vector3<f64>>>(&mut self, angular_factor: T) {
        let angular_factor: BulletVector3 = angular_factor.into().into();
        unsafe {
            sys::btRigidBody_setAngularFactor(self.ptr, angular_factor.0.as_ptr() as *const _);
        }
    }

    pub fn set_sleeping_thresholds(&mut self, linear: f64, angular: f64) {
        unsafe { sys::btRigidBody_setSleepingThresholds(self.ptr, linear, angular) }
    }

    pub fn apply_central_impulse<T: Into<Vector3<f64>>>(&mut self, impulse: T) {
        let impulse: BulletVector3 = impulse.into().into();
        unsafe {
            sys::btRigidBody_applyCentralImpulse(self.ptr, impulse.0.as_ptr() as *const _);
        }
    }

    pub fn get_linear_velocity(&self) -> Vector3<f64> {
        let velocity = unsafe { sys::btRigidBody_getLinearVelocity(self.ptr) };

        ::bullet_vector3::vector_from_slice(unsafe {
            ::std::slice::from_raw_parts(velocity as *const _, 4)
        })
    }

    /// Override velocity vector.
    pub fn reset_linear_velocity<T>(&mut self, vel: T)
    where
        T: Into<Vector3<f64>>,
    {
        let v = vel.into();

        unsafe { (*self.ptr).m_linearVelocity = sys::btVector3::new1(&v.x,&v.y,&v.z); };
    }

    /// Override position vector and rotation quaternion.
    pub fn reset_position_and_orientation<T, T1>(&mut self, position: T, orientation: T1)
    where
        T: Into<Vector3<f64>>,
        T1: Into<Vector4<f64>>,
    {
        let orientation: [f64; 4] = orientation.into().into();
        let position: BulletVector3 = position.into().into();
        let transform = unsafe {
            sys::btTransform::new1(
                &orientation as *const _ as *const _,
                &position as *const _ as *const _,
            )
        };

        unsafe { (*self.ptr)._base.m_worldTransform = transform };
    }

    /// Get position in world space and orientation quaternion
    pub fn get_world_position_and_orientation(&self) -> (Vector3<f64>, Vector4<f64>) {
        unsafe {
            sys::btDefaultMotionState_getWorldTransform(
                &*self.motion_state as *const _ as *mut _,
                &self.temp_transform as *const _ as *mut _,
            );
        }
        let origin = unsafe { self.temp_transform.getOrigin1().as_ref().unwrap() };

        let rotation = unsafe { self.temp_transform.getRotation() };

        (
            ::bullet_vector3::vector_from_slice(&origin.m_floats[0..3]),
            ::bullet_vector3::vector4_from_slice(&rotation._base.m_floats),
        )
    }

    /// Place data on heap as a box and set to rigid body as user pointer
    pub fn set_user_data<T: 'static>(&mut self, data: T) {
        let data_box = Box::new(data);
        unsafe {
            sys::btCollisionObject_setUserPointer(
                self.ptr as *mut _,
                Box::into_raw(data_box) as *mut _,
            )
        };
    }

    /// Get data from rigidbody's user pointer
    /// Getting data from body without previously setted data is fine.
    /// Getting wrong typed data is unsafe and will cause mem::transmute to wrong pointer type.
    pub unsafe fn get_user_data<T: 'static>(&self) -> Option<&T> {
        let pointer = sys::btCollisionObject_getUserPointer(self.ptr as *mut _);
        let pointer: *const T = ::std::mem::transmute(pointer);
        return pointer.as_ref();
    }

    /// Set user index. This will not be used in bullet and this is not related to user_data.
    pub fn set_user_index(&mut self, index: i32) {
        unsafe { sys::btCollisionObject_setUserIndex(self.ptr as *mut _, index) };
    }

    /// Get previously setted user index
    /// If index was not set - will return "-1"
    pub fn get_user_index(&self) -> i32 {
        unsafe { sys::btCollisionObject_getUserIndex(self.ptr as *mut _) }
    }

    /// Was that rigid_body removed with DynamicsWorld::remove_body()
    /// Probably may return true also for any not-added bodys
    pub fn removed(&self) -> bool {
        unsafe { (*self.ptr)._base.m_worldArrayIndex == -1 }
    }
}
<commit_msg>pr fixes<commit_after>use sys;
use bullet_vector3::BulletVector3;
use collision::collision_shapes::Shape;
use mint::{Vector3, Vector4};

pub struct RigidBody {
    rigid_body: Box<sys::btRigidBody>,
    shape: Box<Shape>,
    motion_state: Box<sys::btDefaultMotionState>,
    construction_info: Box<sys::btRigidBody_btRigidBodyConstructionInfo>,
}

impl RigidBody {
    pub fn new<T1: Into<Vector3<f64>>, T2: Into<Vector3<f64>>, T3: Into<Vector4<f64>>>(
        mass: f64,
        inertia: T1,
        shape: Shape,
        translation: T2,
        orientation: T3,
    ) -> RigidBody {
        let mut inertia: BulletVector3 = inertia.into().into();
        let shape_box = Box::new(shape);
        let translation: BulletVector3 = translation.into().into();
        let orientation: [f64; 4] = orientation.into().into();
        let transform = unsafe {
            sys::btTransform::new1(
                &orientation as *const _ as *const _,
                &translation as *const _ as *const _,
            )
        };
        let mut motion_state_box = Box::new(unsafe {
            sys::btDefaultMotionState::new(&transform as *const _, sys::btTransform::getIdentity())
        });

        let construction_info_box = Box::new(unsafe {
            sys::btRigidBody_btRigidBodyConstructionInfo::new(
                mass,
                &mut *motion_state_box as *mut _ as *mut _,
                shape_box.as_ptr(),
                inertia.0.as_mut_ptr() as *mut _,
            )
        });
        RigidBody {
            rigid_body: Box::new(unsafe {
                sys::btRigidBody::new(&*construction_info_box as *const _)
            }),
            shape: shape_box,
            motion_state: motion_state_box,
            construction_info: construction_info_box,
        }
    }

    pub(crate) unsafe fn motion_state_ptr(&self) -> *mut sys::btDefaultMotionState {
        &*self.motion_state as *const _ as *mut _
    }

    pub(crate) unsafe fn as_ptr(&self) -> *mut sys::btRigidBody {
        &*self.rigid_body as *const _ as *mut _
    }
}

#[derive(Clone)]
pub struct RigidBodyHandle {
    pub(in dynamics) ptr: *mut sys::btRigidBody,
    motion_state: *mut sys::btDefaultMotionState,
    temp_transform: sys::btTransform,
}

impl RigidBodyHandle {
    pub fn new(ptr: *mut sys::btRigidBody, motion_state: *mut sys::btDefaultMotionState) -> Self {
        let temp_transform = unsafe { sys::btTransform::new() };

        RigidBodyHandle {
            ptr,
            motion_state,
            temp_transform,
        }
    }
    pub fn set_restitution(&mut self, restitution: f64) {
        unsafe {
            sys::btCollisionObject_setRestitution(self.ptr as *mut _, restitution);
        }
    }
    pub fn set_friction(&mut self, friction: f64) {
        unsafe {
            sys::btCollisionObject_setFriction(self.ptr as *mut _, friction);
        }
    }
    pub fn set_gravity<T: Into<Vector3<f64>>>(&mut self, gravity: T) {
        let gravity: BulletVector3 = gravity.into().into();
        unsafe {
            sys::btRigidBody_setGravity(self.ptr, gravity.0.as_ptr() as *const _);
        }
    }

    pub fn set_angular_factor<T: Into<Vector3<f64>>>(&mut self, angular_factor: T) {
        let angular_factor: BulletVector3 = angular_factor.into().into();
        unsafe {
            sys::btRigidBody_setAngularFactor(self.ptr, angular_factor.0.as_ptr() as *const _);
        }
    }

    pub fn set_sleeping_thresholds(&mut self, linear: f64, angular: f64) {
        unsafe { sys::btRigidBody_setSleepingThresholds(self.ptr, linear, angular) }
    }

    pub fn apply_central_impulse<T: Into<Vector3<f64>>>(&mut self, impulse: T) {
        let impulse: BulletVector3 = impulse.into().into();
        unsafe {
            sys::btRigidBody_applyCentralImpulse(self.ptr, impulse.0.as_ptr() as *const _);
        }
    }

    pub fn get_linear_velocity(&self) -> Vector3<f64> {
        let velocity = unsafe { sys::btRigidBody_getLinearVelocity(self.ptr) };

        ::bullet_vector3::vector_from_slice(unsafe {
            ::std::slice::from_raw_parts(velocity as *const _, 4)
        })
    }

    /// Override velocity vector.
    pub fn reset_linear_velocity<T>(&mut self, velocity: T)
    where
        T: Into<Vector3<f64>>,
    {
        let velocity: BulletVector3 = velocity.into().into();
        unsafe {sys::btRigidBody_setLinearVelocity(self.ptr, velocity.0.as_ptr() as *const _);}
    }

    /// Override position vector and rotation quaternion.
    pub fn reset_position_and_orientation<T, T1>(&mut self, position: T, orientation: T1)
    where
        T: Into<Vector3<f64>>,
        T1: Into<Vector4<f64>>,
    {
        let orientation: [f64; 4] = orientation.into().into();
        let position: BulletVector3 = position.into().into();
        let transform = unsafe {
            sys::btTransform::new1(
                &orientation as *const _ as *const _,
                &position as *const _ as *const _,
            )
        };

        unsafe { (*self.ptr)._base.m_worldTransform = transform };
    }

    /// Get position in world space and orientation quaternion
    pub fn get_world_position_and_orientation(&self) -> (Vector3<f64>, Vector4<f64>) {
        unsafe {
            sys::btDefaultMotionState_getWorldTransform(
                &*self.motion_state as *const _ as *mut _,
                &self.temp_transform as *const _ as *mut _,
            );
        }
        let origin = unsafe { self.temp_transform.getOrigin1().as_ref().unwrap() };

        let rotation = unsafe { self.temp_transform.getRotation() };

        (
            ::bullet_vector3::vector_from_slice(&origin.m_floats[0..3]),
            ::bullet_vector3::vector4_from_slice(&rotation._base.m_floats),
        )
    }

    /// Place data on heap as a box and set to rigid body as user pointer
    pub fn set_user_data<T: 'static>(&mut self, data: T) {
        let data_box = Box::new(data);
        unsafe {
            sys::btCollisionObject_setUserPointer(
                self.ptr as *mut _,
                Box::into_raw(data_box) as *mut _,
            )
        };
    }

    /// Get data from rigidbody's user pointer
    /// Getting data from body without previously setted data is fine.
    /// Getting wrong typed data is unsafe and will cause mem::transmute to wrong pointer type.
    pub unsafe fn get_user_data<T: 'static>(&self) -> Option<&T> {
        let pointer = sys::btCollisionObject_getUserPointer(self.ptr as *mut _);
        let pointer: *const T = ::std::mem::transmute(pointer);
        return pointer.as_ref();
    }

    /// Set user index. This will not be used in bullet and this is not related to user_data.
    pub fn set_user_index(&mut self, index: i32) {
        unsafe { sys::btCollisionObject_setUserIndex(self.ptr as *mut _, index) };
    }

    /// Get previously setted user index
    /// If index was not set - will return "-1"
    pub fn get_user_index(&self) -> i32 {
        unsafe { sys::btCollisionObject_getUserIndex(self.ptr as *mut _) }
    }

    /// Was that rigid_body removed with DynamicsWorld::remove_body()
    /// Probably may return true also for any not-added bodys
    pub fn removed(&self) -> bool {
        unsafe { (*self.ptr)._base.m_worldArrayIndex == -1 }
    }
}
<|endoftext|>


<commit_before>//! Checks the licenses of third-party dependencies by inspecting vendors.

use std::collections::{BTreeSet, HashSet, HashMap};
use std::fs;
use std::path::Path;
use std::process::Command;

use serde_json;

const LICENSES: &[&str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "MIT",
    "Unlicense/MIT",
    "Unlicense OR MIT",
];

/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std/test).
const EXCEPTIONS: &[&str] = &[
    "mdbook",             // MPL2, mdbook
    "openssl",            // BSD+advertising clause, cargo, mdbook
    "pest",               // MPL2, mdbook via handlebars
    "arrayref",           // BSD-2-Clause, mdbook via handlebars via pest
    "thread-id",          // Apache-2.0, mdbook
    "toml-query",         // MPL-2.0, mdbook
    "is-match",           // MPL-2.0, mdbook
    "cssparser",          // MPL-2.0, rustdoc
    "smallvec",           // MPL-2.0, rustdoc
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon",     // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "cssparser-macros",   // MPL-2.0, rustdoc
    "selectors",          // MPL-2.0, rustdoc
    "clippy_lints",       // MPL-2.0, rls
    "colored",            // MPL-2.0, rustfmt
    "ordslice",           // Apache-2.0, rls
    "cloudabi",           // BSD-2-Clause, (rls -> crossbeam-channel 0.2 -> rand 0.5)
    "ryu",                // Apache-2.0, rls/cargo/... (because of serde)
    "bytesize",           // Apache-2.0, cargo
    "im-rc",              // MPL-2.0+, cargo
    "adler32",            // BSD-3-Clause AND Zlib, cargo dep that isn't used
    "fortanix-sgx-abi",   // MPL-2.0+, libstd but only for `sgx` target
    "constant_time_eq",   // CC0-1.0, rustfmt
];

/// Which crates to check against the whitelist?
const WHITELIST_CRATES: &[CrateVersion<'_>] = &[
    CrateVersion("rustc", "0.0.0"),
    CrateVersion("rustc_codegen_llvm", "0.0.0"),
];

/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
const WHITELIST: &[Crate<'_>] = &[
    Crate("adler32"),
    Crate("aho-corasick"),
    Crate("arrayvec"),
    Crate("atty"),
    Crate("backtrace"),
    Crate("backtrace-sys"),
    Crate("bitflags"),
    Crate("build_const"),
    Crate("byteorder"),
    Crate("cc"),
    Crate("cfg-if"),
    Crate("chalk-engine"),
    Crate("chalk-macros"),
    Crate("cloudabi"),
    Crate("cmake"),
    Crate("compiler_builtins"),
    Crate("crc"),
    Crate("crc32fast"),
    Crate("crossbeam-deque"),
    Crate("crossbeam-epoch"),
    Crate("crossbeam-utils"),
    Crate("datafrog"),
    Crate("either"),
    Crate("ena"),
    Crate("env_logger"),
    Crate("filetime"),
    Crate("flate2"),
    Crate("fuchsia-zircon"),
    Crate("fuchsia-zircon-sys"),
    Crate("getopts"),
    Crate("humantime"),
    Crate("jobserver"),
    Crate("kernel32-sys"),
    Crate("lazy_static"),
    Crate("libc"),
    Crate("libz-sys"),
    Crate("lock_api"),
    Crate("log"),
    Crate("log_settings"),
    Crate("memchr"),
    Crate("memmap"),
    Crate("memoffset"),
    Crate("miniz-sys"),
    Crate("miniz_oxide"),
    Crate("miniz_oxide_c_api"),
    Crate("nodrop"),
    Crate("num_cpus"),
    Crate("owning_ref"),
    Crate("parking_lot"),
    Crate("parking_lot_core"),
    Crate("pkg-config"),
    Crate("polonius-engine"),
    Crate("proc-macro2"),
    Crate("quick-error"),
    Crate("quote"),
    Crate("rand"),
    Crate("rand_chacha"),
    Crate("rand_core"),
    Crate("rand_hc"),
    Crate("rand_isaac"),
    Crate("rand_pcg"),
    Crate("rand_xorshift"),
    Crate("redox_syscall"),
    Crate("redox_termios"),
    Crate("regex"),
    Crate("regex-syntax"),
    Crate("remove_dir_all"),
    Crate("rustc-demangle"),
    Crate("rustc-hash"),
    Crate("rustc-rayon"),
    Crate("rustc-rayon-core"),
    Crate("rustc_version"),
    Crate("scoped-tls"),
    Crate("scopeguard"),
    Crate("semver"),
    Crate("semver-parser"),
    Crate("serde"),
    Crate("serde_derive"),
    Crate("smallvec"),
    Crate("stable_deref_trait"),
    Crate("syn"),
    Crate("synstructure"),
    Crate("tempfile"),
    Crate("termcolor"),
    Crate("terminon"),
    Crate("termion"),
    Crate("thread_local"),
    Crate("ucd-util"),
    Crate("unicode-width"),
    Crate("unicode-xid"),
    Crate("unreachable"),
    Crate("utf8-ranges"),
    Crate("vcpkg"),
    Crate("version_check"),
    Crate("void"),
    Crate("winapi"),
    Crate("winapi-build"),
    Crate("winapi-i686-pc-windows-gnu"),
    Crate("winapi-util"),
    Crate("winapi-x86_64-pc-windows-gnu"),
    Crate("wincolor"),
];

// Some types for Serde to deserialize the output of `cargo metadata` to.

#[derive(Deserialize)]
struct Output {
    resolve: Resolve,
}

#[derive(Deserialize)]
struct Resolve {
    nodes: Vec<ResolveNode>,
}

#[derive(Deserialize)]
struct ResolveNode {
    id: String,
    dependencies: Vec<String>,
}

/// A unique identifier for a crate.
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct Crate<'a>(&'a str); // (name)

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct CrateVersion<'a>(&'a str, &'a str); // (name, version)

impl Crate<'_> {
    pub fn id_str(&self) -> String {
        format!("{} ", self.0)
    }
}

impl<'a> CrateVersion<'a> {
    /// Returns the struct and whether or not the dependency is in-tree.
    pub fn from_str(s: &'a str) -> (Self, bool) {
        let mut parts = s.split(' ');
        let name = parts.next().unwrap();
        let version = parts.next().unwrap();
        let path = parts.next().unwrap();

        let is_path_dep = path.starts_with("(path+");

        (CrateVersion(name, version), is_path_dep)
    }

    pub fn id_str(&self) -> String {
        format!("{} {}", self.0, self.1)
    }
}

impl<'a> From<CrateVersion<'a>> for Crate<'a> {
    fn from(cv: CrateVersion<'a>) -> Crate<'a> {
        Crate(cv.0)
    }
}

/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
///
/// Specifically, this checks that the license is correct.
pub fn check(path: &Path, bad: &mut bool) {
    // Check licences.
    let path = path.join("../vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // Skip our exceptions.
        let is_exception = EXCEPTIONS.iter().any(|exception| {
            dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("vendor/{}", exception))
        });
        if is_exception {
            continue;
        }

        let toml = dir.path().join("Cargo.toml");
        *bad = *bad || !check_license(&toml);
    }
    assert!(saw_dir, "no vendored source");
}

/// Checks the dependency of `WHITELIST_CRATES` at the given path. Changes `bad` to `true` if a
/// check failed.
///
/// Specifically, this checks that the dependencies are on the `WHITELIST`.
pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) {
    // Get dependencies from Cargo metadata.
    let resolve = get_deps(path, cargo);

    // Get the whitelist in a convenient form.
    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();

    // Check dependencies.
    let mut visited = BTreeSet::new();
    let mut unapproved = BTreeSet::new();
    for &krate in WHITELIST_CRATES.iter() {
        let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false);
        unapproved.append(&mut bad);
    }

    if !unapproved.is_empty() {
        println!("Dependencies not on the whitelist:");
        for dep in unapproved {
            println!("* {}", dep.id_str());
        }
        *bad = true;
    }

    check_crate_duplicate(&resolve, bad);
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let contents = t!(fs::read_to_string(&path));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1..l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}

/// Gets the dependencies of the crate at the given path using `cargo metadata`.
fn get_deps(path: &Path, cargo: &Path) -> Resolve {
    // Run `cargo metadata` to get the set of dependencies.
    let output = Command::new(cargo)
        .arg("metadata")
        .arg("--format-version")
        .arg("1")
        .arg("--manifest-path")
        .arg(path.join("../Cargo.toml"))
        .output()
        .expect("Unable to run `cargo metadata`")
        .stdout;
    let output = String::from_utf8_lossy(&output);
    let output: Output = serde_json::from_str(&output).unwrap();

    output.resolve
}

/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
/// the whitelist. Returns a list of illegal dependencies.
fn check_crate_whitelist<'a>(
    whitelist: &'a HashSet<Crate<'_>>,
    resolve: &'a Resolve,
    visited: &mut BTreeSet<CrateVersion<'a>>,
    krate: CrateVersion<'a>,
    must_be_on_whitelist: bool,
) -> BTreeSet<Crate<'a>> {
    // This will contain bad deps.
    let mut unapproved = BTreeSet::new();

    // Check if we have already visited this crate.
    if visited.contains(&krate) {
        return unapproved;
    }

    visited.insert(krate);

    // If this path is in-tree, we don't require it to be on the whitelist.
    if must_be_on_whitelist {
        // If this dependency is not on `WHITELIST`, add to bad set.
        if !whitelist.contains(&krate.into()) {
            unapproved.insert(krate.into());
        }
    }

    // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!).
    let to_check = resolve
        .nodes
        .iter()
        .find(|n| n.id.starts_with(&krate.id_str()))
        .expect("crate does not exist");

    for dep in to_check.dependencies.iter() {
        let (krate, is_path_dep) = CrateVersion::from_str(dep);

        let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep);
        unapproved.append(&mut bad);
    }

    unapproved
}

fn check_crate_duplicate(resolve: &Resolve, bad: &mut bool) {
    const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
        // These two crates take quite a long time to build, so don't allow two versions of them
        // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
        // under control.

        "cargo",
        "rustc-ap-syntax",
    ];
    let mut name_to_id: HashMap<_, Vec<_>> = HashMap::new();
    for node in resolve.nodes.iter() {
        name_to_id.entry(node.id.split_whitespace().next().unwrap())
            .or_default()
            .push(&node.id);
    }

    for name in FORBIDDEN_TO_HAVE_DUPLICATES {
        if name_to_id[name].len() <= 1 {
            continue
        }
        println!("crate `{}` is duplicated in `Cargo.lock`", name);
        for id in name_to_id[name].iter() {
            println!("  * {}", id);
        }
        *bad = true;
    }
}
<commit_msg>Allow itertools<commit_after>//! Checks the licenses of third-party dependencies by inspecting vendors.

use std::collections::{BTreeSet, HashSet, HashMap};
use std::fs;
use std::path::Path;
use std::process::Command;

use serde_json;

const LICENSES: &[&str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "MIT",
    "Unlicense/MIT",
    "Unlicense OR MIT",
];

/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std/test).
const EXCEPTIONS: &[&str] = &[
    "mdbook",             // MPL2, mdbook
    "openssl",            // BSD+advertising clause, cargo, mdbook
    "pest",               // MPL2, mdbook via handlebars
    "arrayref",           // BSD-2-Clause, mdbook via handlebars via pest
    "thread-id",          // Apache-2.0, mdbook
    "toml-query",         // MPL-2.0, mdbook
    "is-match",           // MPL-2.0, mdbook
    "cssparser",          // MPL-2.0, rustdoc
    "smallvec",           // MPL-2.0, rustdoc
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon",     // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "cssparser-macros",   // MPL-2.0, rustdoc
    "selectors",          // MPL-2.0, rustdoc
    "clippy_lints",       // MPL-2.0, rls
    "colored",            // MPL-2.0, rustfmt
    "ordslice",           // Apache-2.0, rls
    "cloudabi",           // BSD-2-Clause, (rls -> crossbeam-channel 0.2 -> rand 0.5)
    "ryu",                // Apache-2.0, rls/cargo/... (because of serde)
    "bytesize",           // Apache-2.0, cargo
    "im-rc",              // MPL-2.0+, cargo
    "adler32",            // BSD-3-Clause AND Zlib, cargo dep that isn't used
    "fortanix-sgx-abi",   // MPL-2.0+, libstd but only for `sgx` target
    "constant_time_eq",   // CC0-1.0, rustfmt
];

/// Which crates to check against the whitelist?
const WHITELIST_CRATES: &[CrateVersion<'_>] = &[
    CrateVersion("rustc", "0.0.0"),
    CrateVersion("rustc_codegen_llvm", "0.0.0"),
];

/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
const WHITELIST: &[Crate<'_>] = &[
    Crate("adler32"),
    Crate("aho-corasick"),
    Crate("arrayvec"),
    Crate("atty"),
    Crate("backtrace"),
    Crate("backtrace-sys"),
    Crate("bitflags"),
    Crate("build_const"),
    Crate("byteorder"),
    Crate("cc"),
    Crate("cfg-if"),
    Crate("chalk-engine"),
    Crate("chalk-macros"),
    Crate("cloudabi"),
    Crate("cmake"),
    Crate("compiler_builtins"),
    Crate("crc"),
    Crate("crc32fast"),
    Crate("crossbeam-deque"),
    Crate("crossbeam-epoch"),
    Crate("crossbeam-utils"),
    Crate("datafrog"),
    Crate("either"),
    Crate("ena"),
    Crate("env_logger"),
    Crate("filetime"),
    Crate("flate2"),
    Crate("fuchsia-zircon"),
    Crate("fuchsia-zircon-sys"),
    Crate("getopts"),
    Crate("humantime"),
    Crate("itertools"),
    Crate("jobserver"),
    Crate("kernel32-sys"),
    Crate("lazy_static"),
    Crate("libc"),
    Crate("libz-sys"),
    Crate("lock_api"),
    Crate("log"),
    Crate("log_settings"),
    Crate("memchr"),
    Crate("memmap"),
    Crate("memoffset"),
    Crate("miniz-sys"),
    Crate("miniz_oxide"),
    Crate("miniz_oxide_c_api"),
    Crate("nodrop"),
    Crate("num_cpus"),
    Crate("owning_ref"),
    Crate("parking_lot"),
    Crate("parking_lot_core"),
    Crate("pkg-config"),
    Crate("polonius-engine"),
    Crate("proc-macro2"),
    Crate("quick-error"),
    Crate("quote"),
    Crate("rand"),
    Crate("rand_chacha"),
    Crate("rand_core"),
    Crate("rand_hc"),
    Crate("rand_isaac"),
    Crate("rand_pcg"),
    Crate("rand_xorshift"),
    Crate("redox_syscall"),
    Crate("redox_termios"),
    Crate("regex"),
    Crate("regex-syntax"),
    Crate("remove_dir_all"),
    Crate("rustc-demangle"),
    Crate("rustc-hash"),
    Crate("rustc-rayon"),
    Crate("rustc-rayon-core"),
    Crate("rustc_version"),
    Crate("scoped-tls"),
    Crate("scopeguard"),
    Crate("semver"),
    Crate("semver-parser"),
    Crate("serde"),
    Crate("serde_derive"),
    Crate("smallvec"),
    Crate("stable_deref_trait"),
    Crate("syn"),
    Crate("synstructure"),
    Crate("tempfile"),
    Crate("termcolor"),
    Crate("terminon"),
    Crate("termion"),
    Crate("thread_local"),
    Crate("ucd-util"),
    Crate("unicode-width"),
    Crate("unicode-xid"),
    Crate("unreachable"),
    Crate("utf8-ranges"),
    Crate("vcpkg"),
    Crate("version_check"),
    Crate("void"),
    Crate("winapi"),
    Crate("winapi-build"),
    Crate("winapi-i686-pc-windows-gnu"),
    Crate("winapi-util"),
    Crate("winapi-x86_64-pc-windows-gnu"),
    Crate("wincolor"),
];

// Some types for Serde to deserialize the output of `cargo metadata` to.

#[derive(Deserialize)]
struct Output {
    resolve: Resolve,
}

#[derive(Deserialize)]
struct Resolve {
    nodes: Vec<ResolveNode>,
}

#[derive(Deserialize)]
struct ResolveNode {
    id: String,
    dependencies: Vec<String>,
}

/// A unique identifier for a crate.
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct Crate<'a>(&'a str); // (name)

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct CrateVersion<'a>(&'a str, &'a str); // (name, version)

impl Crate<'_> {
    pub fn id_str(&self) -> String {
        format!("{} ", self.0)
    }
}

impl<'a> CrateVersion<'a> {
    /// Returns the struct and whether or not the dependency is in-tree.
    pub fn from_str(s: &'a str) -> (Self, bool) {
        let mut parts = s.split(' ');
        let name = parts.next().unwrap();
        let version = parts.next().unwrap();
        let path = parts.next().unwrap();

        let is_path_dep = path.starts_with("(path+");

        (CrateVersion(name, version), is_path_dep)
    }

    pub fn id_str(&self) -> String {
        format!("{} {}", self.0, self.1)
    }
}

impl<'a> From<CrateVersion<'a>> for Crate<'a> {
    fn from(cv: CrateVersion<'a>) -> Crate<'a> {
        Crate(cv.0)
    }
}

/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
///
/// Specifically, this checks that the license is correct.
pub fn check(path: &Path, bad: &mut bool) {
    // Check licences.
    let path = path.join("../vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // Skip our exceptions.
        let is_exception = EXCEPTIONS.iter().any(|exception| {
            dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("vendor/{}", exception))
        });
        if is_exception {
            continue;
        }

        let toml = dir.path().join("Cargo.toml");
        *bad = *bad || !check_license(&toml);
    }
    assert!(saw_dir, "no vendored source");
}

/// Checks the dependency of `WHITELIST_CRATES` at the given path. Changes `bad` to `true` if a
/// check failed.
///
/// Specifically, this checks that the dependencies are on the `WHITELIST`.
pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) {
    // Get dependencies from Cargo metadata.
    let resolve = get_deps(path, cargo);

    // Get the whitelist in a convenient form.
    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();

    // Check dependencies.
    let mut visited = BTreeSet::new();
    let mut unapproved = BTreeSet::new();
    for &krate in WHITELIST_CRATES.iter() {
        let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false);
        unapproved.append(&mut bad);
    }

    if !unapproved.is_empty() {
        println!("Dependencies not on the whitelist:");
        for dep in unapproved {
            println!("* {}", dep.id_str());
        }
        *bad = true;
    }

    check_crate_duplicate(&resolve, bad);
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let contents = t!(fs::read_to_string(&path));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1..l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}

/// Gets the dependencies of the crate at the given path using `cargo metadata`.
fn get_deps(path: &Path, cargo: &Path) -> Resolve {
    // Run `cargo metadata` to get the set of dependencies.
    let output = Command::new(cargo)
        .arg("metadata")
        .arg("--format-version")
        .arg("1")
        .arg("--manifest-path")
        .arg(path.join("../Cargo.toml"))
        .output()
        .expect("Unable to run `cargo metadata`")
        .stdout;
    let output = String::from_utf8_lossy(&output);
    let output: Output = serde_json::from_str(&output).unwrap();

    output.resolve
}

/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
/// the whitelist. Returns a list of illegal dependencies.
fn check_crate_whitelist<'a>(
    whitelist: &'a HashSet<Crate<'_>>,
    resolve: &'a Resolve,
    visited: &mut BTreeSet<CrateVersion<'a>>,
    krate: CrateVersion<'a>,
    must_be_on_whitelist: bool,
) -> BTreeSet<Crate<'a>> {
    // This will contain bad deps.
    let mut unapproved = BTreeSet::new();

    // Check if we have already visited this crate.
    if visited.contains(&krate) {
        return unapproved;
    }

    visited.insert(krate);

    // If this path is in-tree, we don't require it to be on the whitelist.
    if must_be_on_whitelist {
        // If this dependency is not on `WHITELIST`, add to bad set.
        if !whitelist.contains(&krate.into()) {
            unapproved.insert(krate.into());
        }
    }

    // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!).
    let to_check = resolve
        .nodes
        .iter()
        .find(|n| n.id.starts_with(&krate.id_str()))
        .expect("crate does not exist");

    for dep in to_check.dependencies.iter() {
        let (krate, is_path_dep) = CrateVersion::from_str(dep);

        let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep);
        unapproved.append(&mut bad);
    }

    unapproved
}

fn check_crate_duplicate(resolve: &Resolve, bad: &mut bool) {
    const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
        // These two crates take quite a long time to build, so don't allow two versions of them
        // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
        // under control.

        "cargo",
        "rustc-ap-syntax",
    ];
    let mut name_to_id: HashMap<_, Vec<_>> = HashMap::new();
    for node in resolve.nodes.iter() {
        name_to_id.entry(node.id.split_whitespace().next().unwrap())
            .or_default()
            .push(&node.id);
    }

    for name in FORBIDDEN_TO_HAVE_DUPLICATES {
        if name_to_id[name].len() <= 1 {
            continue
        }
        println!("crate `{}` is duplicated in `Cargo.lock`", name);
        for id in name_to_id[name].iter() {
            println!("  * {}", id);
        }
        *bad = true;
    }
}
<|endoftext|>


<commit_before>#[cfg(windows)]
extern crate winapi;

extern crate libloading;
use libloading::{Symbol, Library};

const TARGET_DIR: Option<&'static str> = option_env!("CARGO_TARGET_DIR");
const TARGET_TMPDIR: Option<&'static str> = option_env!("CARGO_TARGET_TMPDIR");
static mut LIBPATH: String = String::new();

fn lib_path() -> &'static str {
    static INIT: ::std::sync::Once = ::std::sync::Once::new();

    unsafe {
        INIT.call_once(|| {
            LIBPATH = format!(
                "{}/libtest_helpers.module",
                TARGET_TMPDIR.unwrap_or(TARGET_DIR.unwrap_or("target"))
            );
        });
        &LIBPATH
    }
}

fn make_helpers() {
    static ONCE: ::std::sync::Once = ::std::sync::Once::new();
    ONCE.call_once(|| {
        let rustc = std::env::var_os("RUSTC").unwrap_or_else(|| { "rustc".into() });
        let mut cmd = ::std::process::Command::new(rustc);
        cmd
            .arg("src/test_helpers.rs")
            .arg("-o")
            .arg(lib_path());
        if let Some(target) = std::env::var_os("TARGET") {
            cmd.arg("--target").arg(target);
        } else {
            eprintln!("WARNING: $TARGET NOT SPECIFIED! BUILDING HELPER MODULE FOR NATIVE TARGET.");
        }
        assert!(cmd
            .status()
            .expect("could not compile the test helpers!")
            .success()
        );
    });
}

#[test]
fn test_id_u32() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        let f: Symbol<unsafe extern fn(u32) -> u32> = lib.get(b"test_identity_u32\0").unwrap();
        assert_eq!(42, f(42));
    }
}

#[repr(C)]
#[derive(Clone,Copy,PartialEq,Debug)]
struct S {
    a: u64,
    b: u32,
    c: u16,
    d: u8
}

#[test]
fn test_id_struct() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        let f: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
        assert_eq!(S { a: 1, b: 2, c: 3, d: 4 }, f(S { a: 1, b: 2, c: 3, d: 4 }));
    }
}

#[test]
fn test_0_no_0() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        let f: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
        let f2: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct").unwrap();
        assert_eq!(*f, *f2);
    }
}

#[test]
fn wrong_name_fails() {
    unsafe {
        Library::new("target/this_location_is_definitely_non existent:^~").err().unwrap();
    }
}

#[test]
fn missing_symbol_fails() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        lib.get::<*mut ()>(b"test_does_not_exist").err().unwrap();
        lib.get::<*mut ()>(b"test_does_not_exist\0").err().unwrap();
    }
}

#[test]
fn interior_null_fails() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        lib.get::<*mut ()>(b"test_does\0_not_exist").err().unwrap();
        lib.get::<*mut ()>(b"test\0_does_not_exist\0").err().unwrap();
    }
}

#[test]
fn test_incompatible_type() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        assert!(match lib.get::<()>(b"test_identity_u32\0") {
           Err(libloading::Error::IncompatibleSize) => true,
           _ => false,
        })
    }
}

#[test]
fn test_incompatible_type_named_fn() {
    make_helpers();
    unsafe fn get<'a, T>(l: &'a Library, _: T) -> Result<Symbol<'a, T>, libloading::Error> {
        l.get::<T>(b"test_identity_u32\0")
    }
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        assert!(match get(&lib, test_incompatible_type_named_fn) {
           Err(libloading::Error::IncompatibleSize) => true,
           _ => false,
        })
    }
}

#[test]
fn test_static_u32() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        let var: Symbol<*mut u32> = lib.get(b"TEST_STATIC_U32\0").unwrap();
        **var = 42;
        let help: Symbol<unsafe extern fn() -> u32> = lib.get(b"test_get_static_u32\0").unwrap();
        assert_eq!(42, help());
    }
}

#[test]
fn test_static_ptr() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        let var: Symbol<*mut *mut ()> = lib.get(b"TEST_STATIC_PTR\0").unwrap();
        **var = *var as *mut _;
        let works: Symbol<unsafe extern fn() -> bool> =
            lib.get(b"test_check_static_ptr\0").unwrap();
        assert!(works());
    }
}

#[test]
// Something about i686-pc-windows-gnu, makes dll initialisation code call abort when it is loaded
// and unloaded many times. So far it seems like an issue with mingw, not libloading, so ignoring
// the target. Especially since it is very unlikely to be fixed given the state of support its
// support.
#[cfg(not(all(target_arch="x86", target_os="windows", target_env="gnu")))]
fn manual_close_many_times() {
    make_helpers();
    let join_handles: Vec<_> = (0..16).map(|_| {
        std::thread::spawn(|| unsafe {
            for _ in 0..10000 {
                let lib = Library::new(lib_path()).expect("open library");
                let _: Symbol<unsafe extern fn(u32) -> u32> =
                    lib.get(b"test_identity_u32").expect("get fn");
                lib.close().expect("close is successful");
            }
        })
    }).collect();
    for handle in join_handles {
        handle.join().expect("thread should succeed");
    }
}

#[cfg(unix)]
#[test]
fn library_this_get() {
    use libloading::os::unix::Library;
    make_helpers();
    // SAFE: functions are never called
    unsafe {
        let _lib = Library::new(lib_path()).unwrap();
        let this = Library::this();
        // Library we loaded in `_lib` (should be RTLD_LOCAL).
        assert!(this.get::<unsafe extern "C" fn()>(b"test_identity_u32").is_err());
        // Something obscure from libc...
        assert!(this.get::<unsafe extern "C" fn()>(b"freopen").is_ok());
    }
}

#[cfg(windows)]
#[test]
fn library_this() {
    use libloading::os::windows::Library;
    make_helpers();
    unsafe {
        // SAFE: well-known library without initialisers is loaded.
        let _lib = Library::new(lib_path()).unwrap();
        let this = Library::this().expect("this library");
        // SAFE: functions are never called.
        // Library we loaded in `_lib`.
        assert!(this.get::<unsafe extern "C" fn()>(b"test_identity_u32").is_err());
        // Something "obscure" from kernel32...
        assert!(this.get::<unsafe extern "C" fn()>(b"GetLastError").is_err());
    }
}

#[cfg(windows)]
#[test]
fn works_getlasterror() {
    use winapi::um::errhandlingapi;
    use winapi::shared::minwindef::DWORD;
    use libloading::os::windows::{Library, Symbol};

    unsafe {
        let lib = Library::new("kernel32.dll").unwrap();
        let gle: Symbol<unsafe extern "system" fn() -> DWORD> = lib.get(b"GetLastError").unwrap();
        errhandlingapi::SetLastError(42);
        assert_eq!(errhandlingapi::GetLastError(), gle())
    }
}

#[cfg(windows)]
#[test]
fn works_getlasterror0() {
    use winapi::um::errhandlingapi;
    use winapi::shared::minwindef::DWORD;
    use libloading::os::windows::{Library, Symbol};

    unsafe {
        let lib = Library::new("kernel32.dll").unwrap();
        let gle: Symbol<unsafe extern "system" fn() -> DWORD> = lib.get(b"GetLastError\0").unwrap();
        errhandlingapi::SetLastError(42);
        assert_eq!(errhandlingapi::GetLastError(), gle())
    }
}

#[cfg(windows)]
#[test]
fn library_open_already_loaded() {
    use libloading::os::windows::Library;

    // Present on Windows systems and NOT used by any other tests to prevent races.
    const LIBPATH: &str = "Msftedit.dll";

    // Not loaded yet.
    assert!(match Library::open_already_loaded(LIBPATH) {
        Err(libloading::Error::GetModuleHandleExW { .. }) => true,
        _ => false,
    });

    unsafe {
        let _lib = Library::new(LIBPATH).unwrap();
        // Loaded now.
        assert!(Library::open_already_loaded(LIBPATH).is_ok());
    }
}
<commit_msg>Simplify lib_path<commit_after>#[cfg(windows)]
extern crate winapi;

extern crate libloading;
use libloading::{Library, Symbol};

const TARGET_DIR: Option<&'static str> = option_env!("CARGO_TARGET_DIR");
const TARGET_TMPDIR: Option<&'static str> = option_env!("CARGO_TARGET_TMPDIR");

fn lib_path() -> &'static str {
    format!(
        "{}/libtest_helpers.module",
        TARGET_TMPDIR.unwrap_or(TARGET_DIR.unwrap_or("target"))
    )
}

fn make_helpers() {
    static ONCE: ::std::sync::Once = ::std::sync::Once::new();
    ONCE.call_once(|| {
        let rustc = std::env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
        let mut cmd = ::std::process::Command::new(rustc);
        cmd.arg("src/test_helpers.rs").arg("-o").arg(lib_path());
        if let Some(target) = std::env::var_os("TARGET") {
            cmd.arg("--target").arg(target);
        } else {
            eprintln!("WARNING: $TARGET NOT SPECIFIED! BUILDING HELPER MODULE FOR NATIVE TARGET.");
        }
        assert!(cmd
            .status()
            .expect("could not compile the test helpers!")
            .success());
    });
}

#[test]
fn test_id_u32() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        let f: Symbol<unsafe extern "C" fn(u32) -> u32> = lib.get(b"test_identity_u32\0").unwrap();
        assert_eq!(42, f(42));
    }
}

#[repr(C)]
#[derive(Clone, Copy, PartialEq, Debug)]
struct S {
    a: u64,
    b: u32,
    c: u16,
    d: u8,
}

#[test]
fn test_id_struct() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        let f: Symbol<unsafe extern "C" fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
        assert_eq!(
            S {
                a: 1,
                b: 2,
                c: 3,
                d: 4
            },
            f(S {
                a: 1,
                b: 2,
                c: 3,
                d: 4
            })
        );
    }
}

#[test]
fn test_0_no_0() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        let f: Symbol<unsafe extern "C" fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
        let f2: Symbol<unsafe extern "C" fn(S) -> S> = lib.get(b"test_identity_struct").unwrap();
        assert_eq!(*f, *f2);
    }
}

#[test]
fn wrong_name_fails() {
    unsafe {
        Library::new("target/this_location_is_definitely_non existent:^~")
            .err()
            .unwrap();
    }
}

#[test]
fn missing_symbol_fails() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        lib.get::<*mut ()>(b"test_does_not_exist").err().unwrap();
        lib.get::<*mut ()>(b"test_does_not_exist\0").err().unwrap();
    }
}

#[test]
fn interior_null_fails() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        lib.get::<*mut ()>(b"test_does\0_not_exist").err().unwrap();
        lib.get::<*mut ()>(b"test\0_does_not_exist\0")
            .err()
            .unwrap();
    }
}

#[test]
fn test_incompatible_type() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        assert!(match lib.get::<()>(b"test_identity_u32\0") {
            Err(libloading::Error::IncompatibleSize) => true,
            _ => false,
        })
    }
}

#[test]
fn test_incompatible_type_named_fn() {
    make_helpers();
    unsafe fn get<'a, T>(l: &'a Library, _: T) -> Result<Symbol<'a, T>, libloading::Error> {
        l.get::<T>(b"test_identity_u32\0")
    }
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        assert!(match get(&lib, test_incompatible_type_named_fn) {
            Err(libloading::Error::IncompatibleSize) => true,
            _ => false,
        })
    }
}

#[test]
fn test_static_u32() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        let var: Symbol<*mut u32> = lib.get(b"TEST_STATIC_U32\0").unwrap();
        **var = 42;
        let help: Symbol<unsafe extern "C" fn() -> u32> =
            lib.get(b"test_get_static_u32\0").unwrap();
        assert_eq!(42, help());
    }
}

#[test]
fn test_static_ptr() {
    make_helpers();
    unsafe {
        let lib = Library::new(lib_path()).unwrap();
        let var: Symbol<*mut *mut ()> = lib.get(b"TEST_STATIC_PTR\0").unwrap();
        **var = *var as *mut _;
        let works: Symbol<unsafe extern "C" fn() -> bool> =
            lib.get(b"test_check_static_ptr\0").unwrap();
        assert!(works());
    }
}

#[test]
// Something about i686-pc-windows-gnu, makes dll initialisation code call abort when it is loaded
// and unloaded many times. So far it seems like an issue with mingw, not libloading, so ignoring
// the target. Especially since it is very unlikely to be fixed given the state of support its
// support.
#[cfg(not(all(target_arch = "x86", target_os = "windows", target_env = "gnu")))]
fn manual_close_many_times() {
    make_helpers();
    let join_handles: Vec<_> = (0..16)
        .map(|_| {
            std::thread::spawn(|| unsafe {
                for _ in 0..10000 {
                    let lib = Library::new(lib_path()).expect("open library");
                    let _: Symbol<unsafe extern "C" fn(u32) -> u32> =
                        lib.get(b"test_identity_u32").expect("get fn");
                    lib.close().expect("close is successful");
                }
            })
        })
        .collect();
    for handle in join_handles {
        handle.join().expect("thread should succeed");
    }
}

#[cfg(unix)]
#[test]
fn library_this_get() {
    use libloading::os::unix::Library;
    make_helpers();
    // SAFE: functions are never called
    unsafe {
        let _lib = Library::new(lib_path()).unwrap();
        let this = Library::this();
        // Library we loaded in `_lib` (should be RTLD_LOCAL).
        assert!(this
            .get::<unsafe extern "C" fn()>(b"test_identity_u32")
            .is_err());
        // Something obscure from libc...
        assert!(this.get::<unsafe extern "C" fn()>(b"freopen").is_ok());
    }
}

#[cfg(windows)]
#[test]
fn library_this() {
    use libloading::os::windows::Library;
    make_helpers();
    unsafe {
        // SAFE: well-known library without initialisers is loaded.
        let _lib = Library::new(lib_path()).unwrap();
        let this = Library::this().expect("this library");
        // SAFE: functions are never called.
        // Library we loaded in `_lib`.
        assert!(this
            .get::<unsafe extern "C" fn()>(b"test_identity_u32")
            .is_err());
        // Something "obscure" from kernel32...
        assert!(this.get::<unsafe extern "C" fn()>(b"GetLastError").is_err());
    }
}

#[cfg(windows)]
#[test]
fn works_getlasterror() {
    use libloading::os::windows::{Library, Symbol};
    use winapi::shared::minwindef::DWORD;
    use winapi::um::errhandlingapi;

    unsafe {
        let lib = Library::new("kernel32.dll").unwrap();
        let gle: Symbol<unsafe extern "system" fn() -> DWORD> = lib.get(b"GetLastError").unwrap();
        errhandlingapi::SetLastError(42);
        assert_eq!(errhandlingapi::GetLastError(), gle())
    }
}

#[cfg(windows)]
#[test]
fn works_getlasterror0() {
    use libloading::os::windows::{Library, Symbol};
    use winapi::shared::minwindef::DWORD;
    use winapi::um::errhandlingapi;

    unsafe {
        let lib = Library::new("kernel32.dll").unwrap();
        let gle: Symbol<unsafe extern "system" fn() -> DWORD> = lib.get(b"GetLastError\0").unwrap();
        errhandlingapi::SetLastError(42);
        assert_eq!(errhandlingapi::GetLastError(), gle())
    }
}

#[cfg(windows)]
#[test]
fn library_open_already_loaded() {
    use libloading::os::windows::Library;

    // Present on Windows systems and NOT used by any other tests to prevent races.
    const LIBPATH: &str = "Msftedit.dll";

    // Not loaded yet.
    assert!(match Library::open_already_loaded(LIBPATH) {
        Err(libloading::Error::GetModuleHandleExW { .. }) => true,
        _ => false,
    });

    unsafe {
        let _lib = Library::new(LIBPATH).unwrap();
        // Loaded now.
        assert!(Library::open_already_loaded(LIBPATH).is_ok());
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate kafka;

use test::Bencher;

#[bench]
fn serialise_deserialise_api_request(b: &mut Bencher) {
	b.iter(||{

	});
}

#[bench]
fn serialise_deserialise_api_response(b: &mut Bencher) {
	b.iter(||{

	});
}<commit_msg>Adding simple benches for encoding<commit_after>#![feature(test)]

extern crate kafka;
extern crate test;
extern crate bincode;
extern crate rustc_serialize;

use rustc_serialize::{ Encodable, Decodable };

use bincode::SizeLimit;
use bincode::rustc_serialize::{ encode, decode, DecodingError };

use kafka::protocol::*;

use test::Bencher;

#[derive(RustcEncodable, RustcDecodable)]
pub struct MyRequest {
	pub id: i32,
	pub content: String
}

impl ApiMessage for MyRequest {
	fn get_key(&self) -> i32 {
		self.id
	}
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct MyResponse {
	pub id: i32,
	pub content: String
}

impl ApiMessage for MyResponse {
	fn get_key(&self) -> i32 {
		self.id
	}
}

fn serialise<T: Encodable>(data: &T) -> Vec<u8> {
	encode(data, SizeLimit::Infinite).unwrap()
}
fn deserialise<T: Decodable>(bytes: &[u8]) -> Result<T, DecodingError> {
	decode::<T>(bytes)
}

#[bench]
fn serialise_deserialise_api_request(b: &mut Bencher) {
	let req = ApiRequestMessage {
		request: MyRequest {
			id: 1,
			content: "my request content".to_string()
		},
		api_key: 1,
		api_version: 1,
		correlation_id: 1,
		client_id: "some id".to_string()
	};

	b.iter(||{
		let _ = deserialise::<ApiRequestMessage<MyRequest>>(&serialise(&req)[..]).unwrap();
	});
}

#[bench]
fn serialise_deserialise_api_response(b: &mut Bencher) {
	let res = ApiResponseMessage {
		response: MyResponse {
			id: 1,
			content: "my response content".to_string()
		},
		correlation_id: 1
	};

	b.iter(||{
		let _ = deserialise::<ApiResponseMessage<MyResponse>>(&serialise(&res)[..]).unwrap();
	});
}<|endoftext|>


<commit_before>use crate::discord_client::CommandHandler;
use rusqlite::Connection;
use rusqlite::NO_PARAMS;

pub struct TagCommand {
    tag_repository: TagRepository,
}
pub struct TagRepository {
    db_connection: Connection,
}

impl TagCommand {
    fn new() -> Result<Self, Box<std::error::Error>> {
        let tag_repository = TagRepository::new()?;

        Ok(TagCommand { tag_repository })
    }
}

impl CommandHandler for TagCommand {
    fn process_command(
        &self,
        command: &str,
        send_message_callback: &Fn(&str) -> (),
    ) -> Result<(), Box<std::error::Error>> {
        if command.starts_with("ntag") {

        } else if command.starts_with("atags") {

        } else {

        }
    }
}

impl TagRepository {
    fn new() -> Result<TagRepository, Box<std::error::Error>> {
        let db_connection = Connection::open("tags.db")?;

        db_connection.execute(
            "CREATE TABLE IF NOT EXISTS tags (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL UNIQUE,
            body TEXT NOT NULL
        )",
            NO_PARAMS,
        )?;

        Ok(TagRepository { db_connection })
    }

    fn create_tag(&self, tag_name: &str, tag_body: &str) -> Result<(), Box<std::error::Error>> {
        self.db_connection.execute(
            "INSERT INTO tags
            (name, body) VALUES (?1, ?1)",
            &[tag_name, tag_body],
        )?;
        Ok(())
    }

    fn read_tag(&self, tag_name: &str) -> Result<String, Box<std::error::Error>> {
        Ok(self
            .db_connection
            .prepare(
                "SELECT body
                FROM tags
                WHERE name = (?1)",
            )?
            .query_row(&[tag_name], |row| Ok(row.get(0)?))?)
    }

    fn update_tag(&self, tag_name: &str, tag_body: &str) -> Result<(), Box<std::error::Error>> {
        self.db_connection.execute(
            "UPDATE tags
                SET body = (?2)
                WHERE name = (?1)",
            &[tag_name, tag_body],
        )?;

        Ok(())
    }

    fn delete_tag(&self, tag_name: &str) -> Result<(), Box<std::error::Error>> {
        self.db_connection.execute(
            "DELETE FROM tags
                WHERE name = (?1)",
            &[tag_name],
        )?;

        Ok(())
    }
}
<commit_msg>Some slight reformatting<commit_after>use crate::discord_client::CommandHandler;
use rusqlite::Connection;
use rusqlite::NO_PARAMS;

trait TagRepository {
    fn create_tag(&self, tag_name: &str, tag_body: &str) -> Result<(), Box<std::error::Error>>;
    fn read_tag(&self, tag_name: &str) -> Result<String, Box<std::error::Error>>;
    fn update_tag(&self, tag_name: &str, tag_body: &str) -> Result<(), Box<std::error::Error>>;
    fn delete_tag(&self, tag_name: &str) -> Result<(), Box<std::error::Error>>;
}

pub struct TagCommand {
    tag_repository: Box<TagRepository>,
}
pub struct SqliteTagRepository {
    db_connection: Connection,
}

impl TagCommand {
    fn new() -> Result<TagCommand, Box<std::error::Error>> {
        let tag_repository = Box::new(SqliteTagRepository::new()?);

        Ok(TagCommand { tag_repository })
    }
}

impl CommandHandler for TagCommand {
    fn process_command(
        &self,
        command: &str,
        send_message_callback: &Fn(&str) -> (),
    ) -> Result<(), Box<std::error::Error>> {
        if command.starts_with("ntag") {

        } else if command.starts_with("atags") {

        } else {

        }

        Ok(())
    }
}

impl SqliteTagRepository {
    fn new() -> Result<SqliteTagRepository, Box<std::error::Error>> {
        let db_connection = Connection::open("tags.db")?;

        db_connection.execute(
            "CREATE TABLE IF NOT EXISTS tags (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL UNIQUE,
            body TEXT NOT NULL
        )",
            NO_PARAMS,
        )?;

        Ok(SqliteTagRepository { db_connection })
    }
}

impl TagRepository for SqliteTagRepository {
    fn create_tag(&self, tag_name: &str, tag_body: &str) -> Result<(), Box<std::error::Error>> {
        self.db_connection.execute(
            "INSERT INTO tags
            (name, body) VALUES (?1, ?1)",
            &[tag_name, tag_body],
        )?;
        Ok(())
    }

    fn read_tag(&self, tag_name: &str) -> Result<String, Box<std::error::Error>> {
        Ok(self
            .db_connection
            .prepare(
                "SELECT body
                FROM tags
                WHERE name = (?1)",
            )?
            .query_row(&[tag_name], |row| Ok(row.get(0)?))?)
    }

    fn update_tag(&self, tag_name: &str, tag_body: &str) -> Result<(), Box<std::error::Error>> {
        self.db_connection.execute(
            "UPDATE tags
                SET body = (?2)
                WHERE name = (?1)",
            &[tag_name, tag_body],
        )?;

        Ok(())
    }

    fn delete_tag(&self, tag_name: &str) -> Result<(), Box<std::error::Error>> {
        self.db_connection.execute(
            "DELETE FROM tags
                WHERE name = (?1)",
            &[tag_name],
        )?;

        Ok(())
    }
}
<|endoftext|>


<commit_before>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use decoders::ljpeg::*;
use std::f32::NAN;

#[derive(Debug, Clone)]
pub struct Cr2Decoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> Cr2Decoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> Cr2Decoder<'a> {
    Cr2Decoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for Cr2Decoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let camera = try!(self.rawloader.check_supported(&self.tiff));
    let (raw, offset) = {
      if let Some(raw) = self.tiff.find_first_ifd(Tag::Cr2Id) {
        (raw, fetch_tag!(raw, Tag::StripOffsets).get_usize(0))
      } else if let Some(raw) = self.tiff.find_first_ifd(Tag::CFAPattern) {
        (raw, fetch_tag!(raw, Tag::StripOffsets).get_usize(0))
      } else if let Some(off) = self.tiff.find_entry(Tag::Cr2OldOffset) {
        (&self.tiff, off.get_usize(0))
      } else {
        return Err("CR2: Couldn't find raw info".to_string())
      }
    };
    let src = &self.buffer[offset..];

    let (width, height, cpp, image) = {
      let decompressor = try!(LjpegDecompressor::new(src));
      let mut width = decompressor.width();
      let mut height = decompressor.height();
      let cpp = if decompressor.super_h() == 2 {3} else {1};
      let mut ljpegout = vec![0 as u16; width*height];
      try!(decompressor.decode(&mut ljpegout, 0, width, width, height));

      // Linearize the output (applies only to D2000 as far as I can tell)
      if camera.find_hint("linearization") {
        let table = {
          let linearization = fetch_tag!(self.tiff, Tag::GrayResponse);
          let mut t = [0 as u16;4096];
          for i in 0..t.len() {
            t[i] = linearization.get_u32(i) as u16;
          }
          LookupTable::new(&t)
        };

        let mut random = ljpegout[0] as u32;
        for o in ljpegout.chunks_mut(1) {
          o[0] = table.dither(o[0], &mut random);
        }
      }

      // Convert the YUV in sRAWs to RGB
      if cpp == 3 {
        try!(self.convert_to_rgb(camera, &mut ljpegout));
        if width/cpp < height {
          let temp = width/cpp;
          width = height*cpp;
          height = temp;
        }
      }

      if camera.find_hint("double_line") {
        width /= 2;
        height *= 2;
      }

      // Take each of the vertical fields and put them into the right location
      // FIXME: Doing this at the decode would reduce about 5% in runtime but I haven't
      //        been able to do it without hairy code
      if let Some(canoncol) = raw.find_entry(Tag::Cr2StripeWidths) {
        if canoncol.get_usize(0) == 0 {
          (width, height, cpp, ljpegout)
        } else {
          let mut out = vec![0 as u16; width*height];
          let mut fieldwidths = Vec::new();
          for _ in 0..canoncol.get_usize(0) {
            fieldwidths.push(canoncol.get_usize(1));
          }
          fieldwidths.push(canoncol.get_usize(2));

          if decompressor.super_v() == 2 {
            // We've decoded 2 lines at a time so we also need to copy two strips at a time
            let nfields = fieldwidths.len();
            let fieldwidth = fieldwidths[0];
            let mut fieldstart = 0;
            let mut inpos = 0;
            for _ in 0..nfields {
              let mut row = 0;
              while row < height {
                for _ in 0..nfields {
                  let outpos = row*width+fieldstart;
                  {
                    let outb = &mut out[outpos..outpos+fieldwidth];
                    let inb = &ljpegout[inpos..inpos+fieldwidth];
                    outb.copy_from_slice(inb);
                    row += 1;
                  }
                  let outpos = row*width+fieldstart;
                  let outb = &mut out[outpos..outpos+fieldwidth];
                  let inb = &ljpegout[inpos+width..inpos+width+fieldwidth];
                  outb.copy_from_slice(inb);
                  row += 1;
                  inpos += fieldwidth;
                }
                inpos += width; // skip the line we already used
              }
              fieldstart += fieldwidth;
            }
          } else {
            let sh = decompressor.super_h();
            let mut fieldstart = 0;
            let mut fieldpos = 0;
            for fieldwidth in fieldwidths {
              let fieldwidth = fieldwidth/sh*cpp;
              for row in 0..height {
                let outpos = row*width+fieldstart;
                let inpos = fieldpos+row*fieldwidth;
                let outb = &mut out[outpos..outpos+fieldwidth];
                let inb = &ljpegout[inpos..inpos+fieldwidth];
                outb.copy_from_slice(inb);
              }
              fieldstart += fieldwidth;
              fieldpos += fieldwidth*height;
            }
          }

          (width, height, cpp, out)
        }
      } else {
        (width, height, cpp, ljpegout)
      }
    };

    let mut img = Image::new(camera, width, height, try!(self.get_wb(camera)), image);
    if cpp == 3 {
      img.cpp = 3;
      img.width /= 3;
      img.crops = [0,0,0,0];
      img.blacklevels = [0,0,0,0];
      img.whitelevels = [65535,65535,65535,65535];
    }
    Ok(img)
  }
}

impl<'a> Cr2Decoder<'a> {
  fn get_wb(&self, cam: &Camera) -> Result<[f32;4], String> {
    if let Some(levels) = self.tiff.find_entry(Tag::Cr2ColorData) {
      let offset = if cam.wb_offset != 0 {cam.wb_offset} else {63};
      Ok([levels.get_force_u16(offset) as f32, levels.get_force_u16(offset+1) as f32,
          levels.get_force_u16(offset+3) as f32, NAN])
    } else if let Some(levels) = self.tiff.find_entry(Tag::Cr2PowerShotWB) {
      Ok([levels.get_force_u32(3) as f32, levels.get_force_u32(2) as f32,
          levels.get_force_u32(4) as f32, NAN])
    } else if let Some(levels) = self.tiff.find_entry(Tag::Cr2OldWB) {
      Ok([levels.get_f32(0), levels.get_f32(1), levels.get_f32(2), NAN])
    } else {
      // At least the D2000 has no WB
      Ok([NAN,NAN,NAN,NAN])
    }
  }

  fn convert_to_rgb(&self, cam: &Camera, image: &mut [u16]) -> Result<(),String>{
    let coeffs = try!(self.get_wb(cam));
    let c1 = (1024.0*1024.0/coeffs[0]) as i32;
    let c2 = coeffs[1] as i32;
    let c3 = (1024.0*1024.0/coeffs[2]) as i32;

    for pix in image.chunks_mut(3) {
      let y = pix[0] as i32;
      let cb = pix[1] as i32 - 16383;
      let cr = pix[2] as i32 - 16383;

      let r = c1 * (y + cr);
      let g = c2 * (y + ((-778*cb - (cr<<11)) >> 12));
      let b = c3 * (y + cb);

      pix[0] = clampbits(r >> 8, 16) as u16;
      pix[1] = clampbits(g >> 8, 16) as u16;
      pix[2] = clampbits(b >> 8, 16) as u16;
    }
    Ok(())
  }
}
<commit_msg>CR2: Simplify dimension handling<commit_after>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use decoders::ljpeg::*;
use std::f32::NAN;

#[derive(Debug, Clone)]
pub struct Cr2Decoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> Cr2Decoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> Cr2Decoder<'a> {
    Cr2Decoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for Cr2Decoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let camera = try!(self.rawloader.check_supported(&self.tiff));
    let (raw, offset) = {
      if let Some(raw) = self.tiff.find_first_ifd(Tag::Cr2Id) {
        (raw, fetch_tag!(raw, Tag::StripOffsets).get_usize(0))
      } else if let Some(raw) = self.tiff.find_first_ifd(Tag::CFAPattern) {
        (raw, fetch_tag!(raw, Tag::StripOffsets).get_usize(0))
      } else if let Some(off) = self.tiff.find_entry(Tag::Cr2OldOffset) {
        (&self.tiff, off.get_usize(0))
      } else {
        return Err("CR2: Couldn't find raw info".to_string())
      }
    };
    let src = &self.buffer[offset..];

    let (width, height, cpp, image) = {
      let decompressor = try!(LjpegDecompressor::new(src));
      let mut width = decompressor.width();
      let mut height = decompressor.height();
      let cpp = if decompressor.super_h() == 2 {3} else {1};
      let mut ljpegout = vec![0 as u16; width*height];
      try!(decompressor.decode(&mut ljpegout, 0, width, width, height));

      // Linearize the output (applies only to D2000 as far as I can tell)
      if camera.find_hint("linearization") {
        let table = {
          let linearization = fetch_tag!(self.tiff, Tag::GrayResponse);
          let mut t = [0 as u16;4096];
          for i in 0..t.len() {
            t[i] = linearization.get_u32(i) as u16;
          }
          LookupTable::new(&t)
        };

        let mut random = ljpegout[0] as u32;
        for o in ljpegout.chunks_mut(1) {
          o[0] = table.dither(o[0], &mut random);
        }
      }

      // Convert the YUV in sRAWs to RGB
      if cpp == 3 {
        try!(self.convert_to_rgb(camera, &mut ljpegout));
      }

      if raw.has_entry(Tag::ImageWidth) {
        width = fetch_tag!(raw, Tag::ImageWidth).get_usize(0) * cpp;
        height = fetch_tag!(raw, Tag::ImageLength).get_usize(0) ;
      } else if width/cpp < height {
        let temp = width/cpp;
        width = height*cpp;
        height = temp;
      } else if camera.find_hint("double_line") {
        width /= 2;
        height *= 2;
      }

      // Take each of the vertical fields and put them into the right location
      // FIXME: Doing this at the decode would reduce about 5% in runtime but I haven't
      //        been able to do it without hairy code
      if let Some(canoncol) = raw.find_entry(Tag::Cr2StripeWidths) {
        if canoncol.get_usize(0) == 0 {
          (width, height, cpp, ljpegout)
        } else {
          let mut out = vec![0 as u16; width*height];
          let mut fieldwidths = Vec::new();
          for _ in 0..canoncol.get_usize(0) {
            fieldwidths.push(canoncol.get_usize(1));
          }
          fieldwidths.push(canoncol.get_usize(2));

          if decompressor.super_v() == 2 {
            // We've decoded 2 lines at a time so we also need to copy two strips at a time
            let nfields = fieldwidths.len();
            let fieldwidth = fieldwidths[0];
            let mut fieldstart = 0;
            let mut inpos = 0;
            for _ in 0..nfields {
              let mut row = 0;
              while row < height {
                for _ in 0..nfields {
                  let outpos = row*width+fieldstart;
                  {
                    let outb = &mut out[outpos..outpos+fieldwidth];
                    let inb = &ljpegout[inpos..inpos+fieldwidth];
                    outb.copy_from_slice(inb);
                    row += 1;
                  }
                  let outpos = row*width+fieldstart;
                  let outb = &mut out[outpos..outpos+fieldwidth];
                  let inb = &ljpegout[inpos+width..inpos+width+fieldwidth];
                  outb.copy_from_slice(inb);
                  row += 1;
                  inpos += fieldwidth;
                }
                inpos += width; // skip the line we already used
              }
              fieldstart += fieldwidth;
            }
          } else {
            let sh = decompressor.super_h();
            let mut fieldstart = 0;
            let mut fieldpos = 0;
            for fieldwidth in fieldwidths {
              let fieldwidth = fieldwidth/sh*cpp;
              for row in 0..height {
                let outpos = row*width+fieldstart;
                let inpos = fieldpos+row*fieldwidth;
                let outb = &mut out[outpos..outpos+fieldwidth];
                let inb = &ljpegout[inpos..inpos+fieldwidth];
                outb.copy_from_slice(inb);
              }
              fieldstart += fieldwidth;
              fieldpos += fieldwidth*height;
            }
          }

          (width, height, cpp, out)
        }
      } else {
        (width, height, cpp, ljpegout)
      }
    };

    let mut img = Image::new(camera, width, height, try!(self.get_wb(camera)), image);
    if cpp == 3 {
      img.cpp = 3;
      img.width /= 3;
      img.crops = [0,0,0,0];
      img.blacklevels = [0,0,0,0];
      img.whitelevels = [65535,65535,65535,65535];
    }
    Ok(img)
  }
}

impl<'a> Cr2Decoder<'a> {
  fn get_wb(&self, cam: &Camera) -> Result<[f32;4], String> {
    if let Some(levels) = self.tiff.find_entry(Tag::Cr2ColorData) {
      let offset = if cam.wb_offset != 0 {cam.wb_offset} else {63};
      Ok([levels.get_force_u16(offset) as f32, levels.get_force_u16(offset+1) as f32,
          levels.get_force_u16(offset+3) as f32, NAN])
    } else if let Some(levels) = self.tiff.find_entry(Tag::Cr2PowerShotWB) {
      Ok([levels.get_force_u32(3) as f32, levels.get_force_u32(2) as f32,
          levels.get_force_u32(4) as f32, NAN])
    } else if let Some(levels) = self.tiff.find_entry(Tag::Cr2OldWB) {
      Ok([levels.get_f32(0), levels.get_f32(1), levels.get_f32(2), NAN])
    } else {
      // At least the D2000 has no WB
      Ok([NAN,NAN,NAN,NAN])
    }
  }

  fn convert_to_rgb(&self, cam: &Camera, image: &mut [u16]) -> Result<(),String>{
    let coeffs = try!(self.get_wb(cam));
    let c1 = (1024.0*1024.0/coeffs[0]) as i32;
    let c2 = coeffs[1] as i32;
    let c3 = (1024.0*1024.0/coeffs[2]) as i32;

    for pix in image.chunks_mut(3) {
      let y = pix[0] as i32;
      let cb = pix[1] as i32 - 16383;
      let cr = pix[2] as i32 - 16383;

      let r = c1 * (y + cr);
      let g = c2 * (y + ((-778*cb - (cr<<11)) >> 12));
      let b = c3 * (y + cb);

      pix[0] = clampbits(r >> 8, 16) as u16;
      pix[1] = clampbits(g >> 8, 16) as u16;
      pix[2] = clampbits(b >> 8, 16) as u16;
    }
    Ok(())
  }
}
<|endoftext|>