<commit_before>#![allow(non_camel_case_types)]

extern crate libc;
use libc::{uint32_t, int32_t, uint64_t, int64_t, c_uchar, size_t, c_void, c_uint};

pub type sph_u32 = uint32_t;
pub type sph_s32 = int32_t;

#[repr(C)]
#[allow(non_snake_case)]
pub struct BlakeSmallContext {
    pub buf: [c_uchar; 64usize],
    pub ptr: size_t,
    pub H: [sph_u32; 8usize],
    pub S: [sph_u32; 4usize],
    pub T0: sph_u32,
    pub T1: sph_u32,
}

impl ::std::default::Default for BlakeSmallContext {
    fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}

pub type sph_blake_small_context = BlakeSmallContext;
pub type sph_blake224_context = sph_blake_small_context;
pub type sph_blake256_context = sph_blake_small_context;

pub type sph_u64 = uint64_t;
pub type sph_s64 = int64_t;

#[repr(C)]
#[allow(non_snake_case)]
pub struct BlakeBigContext {
    pub buf: [c_uchar; 128usize],
    pub ptr: size_t,
    pub H: [sph_u64; 8usize],
    pub S: [sph_u64; 4usize],
    pub T0: sph_u64,
    pub T1: sph_u64,
}

impl ::std::default::Default for BlakeBigContext {
    fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}

pub type sph_blake_big_context = BlakeBigContext;
pub type sph_blake384_context = sph_blake_big_context;
pub type sph_blake512_context = sph_blake_big_context;

extern {
    pub fn sph_blake224_init(cc: *mut c_void) -> ();
    pub fn sph_blake224(cc: *mut c_void, data: *const c_void, len: size_t) -> ();
    pub fn sph_blake224_close(cc: *mut c_void, dst: *mut c_void) -> ();
    pub fn sph_blake224_addbits_and_close(cc: *mut c_void, ub: c_uint, n: c_uint, dst: *mut c_void) -> ();

    pub fn sph_blake256_init(cc: *mut c_void) -> ();
    pub fn sph_blake256(cc: *mut c_void, data: *const c_void, len: size_t) -> ();
    pub fn sph_blake256_close(cc: *mut c_void, dst: *mut c_void) -> ();
    pub fn sph_blake256_addbits_and_close(cc: *mut c_void, ub: c_uint, n: c_uint, dst: *mut c_void) -> ();

    pub fn sph_blake384_init(cc: *mut c_void) -> ();
    pub fn sph_blake384(cc: *mut c_void, data: *const c_void, len: size_t) -> ();
    pub fn sph_blake384_close(cc: *mut c_void, dst: *mut c_void) -> ();
    pub fn sph_blake384_addbits_and_close(cc: *mut c_void, ub: c_uint, n: c_uint, dst: *mut c_void) -> ();

    pub fn sph_blake512_init(cc: *mut c_void) -> ();
    pub fn sph_blake512(cc: *mut c_void, data: *const c_void, len: size_t) -> ();
    pub fn sph_blake512_close(cc: *mut c_void, dst: *mut c_void) -> ();
    pub fn sph_blake512_addbits_and_close(cc: *mut c_void, ub: c_uint, n: c_uint, dst: *mut c_void) -> ();
}

pub fn blake224(data: &str) -> [u8;28] {
    let mut dest: [u8;28] = [0;28];
    unsafe {
        let mut cc = BlakeSmallContext::default();
        let raw_cc = &mut cc as *mut BlakeSmallContext;
        let void_raw_cc = raw_cc as *mut c_void;
        // FIXME Figure out what's wrong here `let void_raw_cc = to_void_raw_small_ctx()`;
        sph_blake224_init(void_raw_cc);

        let (void_raw_data, len) = to_void_raw_data(data);
        sph_blake224(void_raw_cc, void_raw_data, len);

        let void_raw_dest = to_void_raw_dest(&mut dest);
        sph_blake224_close(void_raw_cc, void_raw_dest);
    }
    return dest;
}

pub fn blake256(data: &str) -> [u8;32] {
    let mut dest: [u8;32] = [0;32];
    unsafe {
        let mut cc = BlakeSmallContext::default();
        let raw_cc = &mut cc as *mut BlakeSmallContext;
        let void_raw_cc = raw_cc as *mut c_void;
        // FIXME Figure out what's wrong here `let void_raw_cc = to_void_raw_small_ctx()`;
        sph_blake256_init(void_raw_cc);

        let (void_raw_data, len) = to_void_raw_data(data);
        sph_blake256(void_raw_cc, void_raw_data, len);

        let void_raw_dest = to_void_raw_dest(&mut dest);
        sph_blake256_close(void_raw_cc, void_raw_dest);
    }
    return dest;
}

pub fn blake384(data: &str) -> [u8;48] {
    let mut dest: [u8;48] = [0;48];
    unsafe {
        let mut cc = BlakeBigContext::default();
        let raw_cc = &mut cc as *mut BlakeBigContext;
        let void_raw_cc = raw_cc as *mut c_void;
        // FIXME Figure out what's wrong here `let void_raw_cc = to_void_raw_small_ctx()`;
        sph_blake384_init(void_raw_cc);

        let (void_raw_data, len) = to_void_raw_data(data);
        sph_blake384(void_raw_cc, void_raw_data, len);

        let void_raw_dest = to_void_raw_dest(&mut dest);
        sph_blake384_close(void_raw_cc, void_raw_dest);
    }
    return dest;
}

pub fn blake512(data: &str) -> [u8;64] {
    let mut dest: [u8;64] = [0;64];
    unsafe {
        let mut cc = BlakeBigContext::default();
        let raw_cc = &mut cc as *mut BlakeBigContext;
        let void_raw_cc = raw_cc as *mut c_void;
        // FIXME Figure out what's wrong here `let void_raw_cc = to_void_raw_small_ctx()`;
        sph_blake512_init(void_raw_cc);

        let (void_raw_data, len) = to_void_raw_data(data);
        sph_blake512(void_raw_cc, void_raw_data, len);

        let void_raw_dest = to_void_raw_dest(&mut dest);
        sph_blake512_close(void_raw_cc, void_raw_dest);
    }
    return dest;
}

// private

#[allow(dead_code)]
fn to_void_raw_small_ctx() -> *mut c_void {
    let mut cc = BlakeSmallContext::default();
    let raw_cc = &mut cc as *mut BlakeSmallContext;
    let void_raw_cc = raw_cc as *mut c_void;

    return void_raw_cc;
}

fn to_void_raw_data(data: &str) -> (*const c_void, size_t) {
    let void_raw_data = data.as_ptr() as *const c_void;
    let len = data.len() as size_t;

    return (void_raw_data, len);
}

fn to_void_raw_dest(dest: &mut [u8]) -> *mut c_void {
    let raw_dest = dest.as_mut() as *mut [u8];
    let void_raw_dest = raw_dest as *mut c_void;

    return void_raw_dest;
}
<commit_msg>Extract generic context builder<commit_after>#![allow(non_camel_case_types)]

extern crate libc;
use libc::{uint32_t, int32_t, uint64_t, int64_t, c_uchar, size_t, c_void, c_uint};

pub type sph_u32 = uint32_t;
pub type sph_s32 = int32_t;

#[repr(C)]
#[allow(non_snake_case)]
pub struct BlakeSmallContext {
    pub buf: [c_uchar; 64usize],
    pub ptr: size_t,
    pub H: [sph_u32; 8usize],
    pub S: [sph_u32; 4usize],
    pub T0: sph_u32,
    pub T1: sph_u32,
}

impl ::std::default::Default for BlakeSmallContext {
    fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}

pub type sph_blake_small_context = BlakeSmallContext;
pub type sph_blake224_context = sph_blake_small_context;
pub type sph_blake256_context = sph_blake_small_context;

pub type sph_u64 = uint64_t;
pub type sph_s64 = int64_t;

#[repr(C)]
#[allow(non_snake_case)]
pub struct BlakeBigContext {
    pub buf: [c_uchar; 128usize],
    pub ptr: size_t,
    pub H: [sph_u64; 8usize],
    pub S: [sph_u64; 4usize],
    pub T0: sph_u64,
    pub T1: sph_u64,
}

impl ::std::default::Default for BlakeBigContext {
    fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}

pub type sph_blake_big_context = BlakeBigContext;
pub type sph_blake384_context = sph_blake_big_context;
pub type sph_blake512_context = sph_blake_big_context;

extern {
    pub fn sph_blake224_init(cc: *mut c_void) -> ();
    pub fn sph_blake224(cc: *mut c_void, data: *const c_void, len: size_t) -> ();
    pub fn sph_blake224_close(cc: *mut c_void, dst: *mut c_void) -> ();
    pub fn sph_blake224_addbits_and_close(cc: *mut c_void, ub: c_uint, n: c_uint, dst: *mut c_void) -> ();

    pub fn sph_blake256_init(cc: *mut c_void) -> ();
    pub fn sph_blake256(cc: *mut c_void, data: *const c_void, len: size_t) -> ();
    pub fn sph_blake256_close(cc: *mut c_void, dst: *mut c_void) -> ();
    pub fn sph_blake256_addbits_and_close(cc: *mut c_void, ub: c_uint, n: c_uint, dst: *mut c_void) -> ();

    pub fn sph_blake384_init(cc: *mut c_void) -> ();
    pub fn sph_blake384(cc: *mut c_void, data: *const c_void, len: size_t) -> ();
    pub fn sph_blake384_close(cc: *mut c_void, dst: *mut c_void) -> ();
    pub fn sph_blake384_addbits_and_close(cc: *mut c_void, ub: c_uint, n: c_uint, dst: *mut c_void) -> ();

    pub fn sph_blake512_init(cc: *mut c_void) -> ();
    pub fn sph_blake512(cc: *mut c_void, data: *const c_void, len: size_t) -> ();
    pub fn sph_blake512_close(cc: *mut c_void, dst: *mut c_void) -> ();
    pub fn sph_blake512_addbits_and_close(cc: *mut c_void, ub: c_uint, n: c_uint, dst: *mut c_void) -> ();
}

pub fn blake224(data: &str) -> [u8;28] {
    let mut dest: [u8;28] = [0;28];
    unsafe {
        let mut cc      = BlakeSmallContext::default();
        let void_raw_cc = to_void_raw_ctx(&mut cc);
        sph_blake224_init(void_raw_cc);

        let (void_raw_data, len) = to_void_raw_data(data);
        sph_blake224(void_raw_cc, void_raw_data, len);

        let void_raw_dest = to_void_raw_dest(&mut dest);
        sph_blake224_close(void_raw_cc, void_raw_dest);
    }
    return dest;
}

pub fn blake256(data: &str) -> [u8;32] {
    let mut dest: [u8;32] = [0;32];
    unsafe {
        let mut cc      = BlakeSmallContext::default();
        let void_raw_cc = to_void_raw_ctx(&mut cc);
        sph_blake256_init(void_raw_cc);

        let (void_raw_data, len) = to_void_raw_data(data);
        sph_blake256(void_raw_cc, void_raw_data, len);

        let void_raw_dest = to_void_raw_dest(&mut dest);
        sph_blake256_close(void_raw_cc, void_raw_dest);
    }
    return dest;
}

pub fn blake384(data: &str) -> [u8;48] {
    let mut dest: [u8;48] = [0;48];
    unsafe {
        let mut cc      = BlakeBigContext::default();
        let void_raw_cc = to_void_raw_ctx(&mut cc);
        sph_blake384_init(void_raw_cc);

        let (void_raw_data, len) = to_void_raw_data(data);
        sph_blake384(void_raw_cc, void_raw_data, len);

        let void_raw_dest = to_void_raw_dest(&mut dest);
        sph_blake384_close(void_raw_cc, void_raw_dest);
    }
    return dest;
}

pub fn blake512(data: &str) -> [u8;64] {
    let mut dest: [u8;64] = [0;64];
    unsafe {
        let mut cc      = BlakeBigContext::default();
        let void_raw_cc = to_void_raw_ctx(&mut cc);
        sph_blake512_init(void_raw_cc);

        let (void_raw_data, len) = to_void_raw_data(data);
        sph_blake512(void_raw_cc, void_raw_data, len);

        let void_raw_dest = to_void_raw_dest(&mut dest);
        sph_blake512_close(void_raw_cc, void_raw_dest);
    }
    return dest;
}

// private

fn to_void_raw_ctx<T>(cc: &mut T) -> *mut c_void {
    let raw_cc      = cc as *mut T;
    let void_raw_cc = raw_cc as *mut c_void;

    return void_raw_cc;
}

fn to_void_raw_data(data: &str) -> (*const c_void, size_t) {
    let void_raw_data = data.as_ptr() as *const c_void;
    let len = data.len() as size_t;

    return (void_raw_data, len);
}

fn to_void_raw_dest(dest: &mut [u8]) -> *mut c_void {
    let raw_dest = dest.as_mut() as *mut [u8];
    let void_raw_dest = raw_dest as *mut c_void;

    return void_raw_dest;
}
<|endoftext|>


<commit_before>use {Errno, Result};
use libc::{self, c_int};
use std::os::unix::io::RawFd;

bitflags!(
    #[repr(C)]
    flags EpollEventKind: u32 {
        const EPOLLIN = 0x001,
        const EPOLLPRI = 0x002,
        const EPOLLOUT = 0x004,
        const EPOLLRDNORM = 0x040,
        const EPOLLRDBAND = 0x080,
        const EPOLLWRNORM = 0x100,
        const EPOLLWRBAND = 0x200,
        const EPOLLMSG = 0x400,
        const EPOLLERR = 0x008,
        const EPOLLHUP = 0x010,
        const EPOLLRDHUP = 0x2000,
        const EPOLLEXCLUSIVE = 1 << 28,
        const EPOLLWAKEUP = 1 << 29,
        const EPOLLONESHOT = 1 << 30,
        const EPOLLET = 1 << 31
    }
);

#[derive(Clone, Copy)]
#[repr(C)]
pub enum EpollOp {
    EpollCtlAdd = 1,
    EpollCtlDel = 2,
    EpollCtlMod = 3
}

#[inline]
pub fn epoll_create() -> Result<RawFd> {
    let res = unsafe { libc::epoll_create(1024) };

    Errno::result(res)
}

#[inline]
pub fn epoll_create1(flags: c_int) -> Result<RawFd> {
    let res = unsafe { libc::epoll_create1(flags) };

    Errno::result(res)
}

#[inline]
pub fn epoll_ctl(epfd: RawFd, op: EpollOp, fd: RawFd, event: &mut libc::epoll_event) -> Result<()> {
    let res = unsafe { libc::epoll_ctl(epfd, op as c_int, fd, event as *mut libc::epoll_event) };

    Errno::result(res).map(drop)
}

#[inline]
pub fn epoll_wait(epfd: RawFd, events: &mut [libc::epoll_event], timeout_ms: isize) -> Result<usize> {
    let res = unsafe {
        libc::epoll_wait(epfd, events.as_mut_ptr(), events.len() as c_int, timeout_ms as c_int)
    };

    Errno::result(res).map(|r| r as usize)
}
<commit_msg>Readd EpollEvent<commit_after>use {Errno, Result};
use libc::{self, c_int};
use std::os::unix::io::RawFd;

bitflags!(
    #[repr(C)]
    flags EpollEventKind: u32 {
        const EPOLLIN = 0x001,
        const EPOLLPRI = 0x002,
        const EPOLLOUT = 0x004,
        const EPOLLRDNORM = 0x040,
        const EPOLLRDBAND = 0x080,
        const EPOLLWRNORM = 0x100,
        const EPOLLWRBAND = 0x200,
        const EPOLLMSG = 0x400,
        const EPOLLERR = 0x008,
        const EPOLLHUP = 0x010,
        const EPOLLRDHUP = 0x2000,
        const EPOLLEXCLUSIVE = 1 << 28,
        const EPOLLWAKEUP = 1 << 29,
        const EPOLLONESHOT = 1 << 30,
        const EPOLLET = 1 << 31
    }
);

#[derive(Clone, Copy)]
#[repr(C)]
pub enum EpollOp {
    EpollCtlAdd = 1,
    EpollCtlDel = 2,
    EpollCtlMod = 3
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct EpollEvent {
    event: libc::epoll_event,
}

impl EpollEvent {
    fn new(events: EpollEventKind, data: u64) -> EpollEvent {
        EpollEvent { event: libc::epoll_event { events: events.bits(), u64: data } }
    }
}

#[inline]
pub fn epoll_create() -> Result<RawFd> {
    let res = unsafe { libc::epoll_create(1024) };

    Errno::result(res)
}

#[inline]
pub fn epoll_create1(flags: c_int) -> Result<RawFd> {
    let res = unsafe { libc::epoll_create1(flags) };

    Errno::result(res)
}

#[inline]
pub fn epoll_ctl(epfd: RawFd, op: EpollOp, fd: RawFd, event: &mut EpollEvent) -> Result<()> {
    let res = unsafe { libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event) };

    Errno::result(res).map(drop)
}

#[inline]
pub fn epoll_wait(epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize) -> Result<usize> {
    let res = unsafe {
        libc::epoll_wait(epfd, events.as_mut_ptr() as *mut libc::epoll_event, events.len() as c_int, timeout_ms as c_int)
    };

    Errno::result(res).map(|r| r as usize)
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::rc::Rc;
use super::{Addr, Addressable};

/// Shared memory. Allows some arbitrary memory to be shared by cloning.
pub struct SharedMemory<M> {
	priv mem: Rc<RefCell<M>>,
}

impl<A: Addr, M: Addressable<A> + Freeze> SharedMemory<M> {
	/// Create new shared memory of the given memory object
	pub fn new (mem: M) -> SharedMemory<M> {
		SharedMemory { mem: Rc::from_mut(RefCell::new(mem)) }
	}
}

impl<A: Addr, M: Addressable<A>> Addressable<A> for SharedMemory<M> {
	fn get (&self, addr: A) -> u8 {
		self.mem.borrow().with(|mem| mem.get(addr.clone()))
	}

	fn set (&mut self, addr: A, data: u8) {
		self.mem.borrow().with_mut(|mem| mem.set(addr.clone(), data));
	}
}

impl<A: Addr, M: Addressable<A>> Clone for SharedMemory<M> {
	fn clone (&self) -> SharedMemory<M> {
		SharedMemory { mem: self.mem.clone() }
	}
}

#[cfg(test)]
mod test {
	use super::super::Addressable;
	use super::SharedMemory;

	struct TestMemory {
		mem: [u8, ..256],
	}
	impl Addressable<u8> for TestMemory {
		fn get (&self, addr: u8) -> u8 { self.mem[addr] }
		fn set (&mut self, addr: u8, data: u8) { self.mem[addr] = data; }
	}

	#[test]
	fn read_write () {
		let mut mem = TestMemory { mem: [0, ..256] };
		mem.set(0x12, 0x34);
		let mut shmem = SharedMemory::new(mem);
		assert_eq!(shmem.get(0x12), 0x34);
		shmem.set(0x56, 0x78);
		assert_eq!(shmem.get(0x56), 0x78);
	}

	#[test]
	fn read_write_cloned () {
		let mut mem = TestMemory { mem: [0, ..256] };
		mem.set(0x12, 0x34);
		let mut shmem1 = SharedMemory::new(mem);
		let mut shmem2 = shmem1.clone();
		assert_eq!(shmem2.get(0x12), 0x34);
		shmem1.set(0x56, 0x78);
		assert_eq!(shmem2.get(0x56), 0x78);
		shmem2.set(0x9a, 0xbc);
		assert_eq!(shmem1.get(0x9a), 0xbc);
	}
}
<commit_msg>Rc::from_mut can now be done with Rc::new<commit_after>use std::cell::RefCell;
use std::rc::Rc;
use super::{Addr, Addressable};

/// Shared memory. Allows some arbitrary memory to be shared by cloning.
pub struct SharedMemory<M> {
	priv mem: Rc<RefCell<M>>,
}

impl<A: Addr, M: Addressable<A>> SharedMemory<M> {
	/// Create new shared memory of the given memory object
	pub fn new (mem: M) -> SharedMemory<M> {
		SharedMemory { mem: Rc::new(RefCell::new(mem)) }
	}
}

impl<A: Addr, M: Addressable<A>> Addressable<A> for SharedMemory<M> {
	fn get (&self, addr: A) -> u8 {
		self.mem.borrow().with(|mem| mem.get(addr.clone()))
	}

	fn set (&mut self, addr: A, data: u8) {
		self.mem.borrow().with_mut(|mem| mem.set(addr.clone(), data));
	}
}

impl<A: Addr, M: Addressable<A>> Clone for SharedMemory<M> {
	fn clone (&self) -> SharedMemory<M> {
		SharedMemory { mem: self.mem.clone() }
	}
}

#[cfg(test)]
mod test {
	use super::super::Addressable;
	use super::SharedMemory;

	struct TestMemory {
		mem: [u8, ..256],
	}
	impl Addressable<u8> for TestMemory {
		fn get (&self, addr: u8) -> u8 { self.mem[addr] }
		fn set (&mut self, addr: u8, data: u8) { self.mem[addr] = data; }
	}

	#[test]
	fn read_write () {
		let mut mem = TestMemory { mem: [0, ..256] };
		mem.set(0x12, 0x34);
		let mut shmem = SharedMemory::new(mem);
		assert_eq!(shmem.get(0x12), 0x34);
		shmem.set(0x56, 0x78);
		assert_eq!(shmem.get(0x56), 0x78);
	}

	#[test]
	fn read_write_cloned () {
		let mut mem = TestMemory { mem: [0, ..256] };
		mem.set(0x12, 0x34);
		let mut shmem1 = SharedMemory::new(mem);
		let mut shmem2 = shmem1.clone();
		assert_eq!(shmem2.get(0x12), 0x34);
		shmem1.set(0x56, 0x78);
		assert_eq!(shmem2.get(0x56), 0x78);
		shmem2.set(0x9a, 0xbc);
		assert_eq!(shmem1.get(0x9a), 0xbc);
	}
}
<|endoftext|>


<commit_before>//! Provide access to locally cached memdb SDKs
//!
//! The `MemDbStash` pulls in remote SDKs from an S3 bucket and provides
//! access to it.  This is used by the symbol server to manage the local
//! cache and also to refer to memdb files that are mmap'ed in.
use std::fs;
use std::io;
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Values as HashMapValuesIter;
use std::sync::{Arc, RwLock};

use serde_json;
use xz2::write::XzDecoder;
use chrono::UTC;

use super::config::Config;
use super::sdk::SdkInfo;
use super::s3::S3;
use super::memdb::MemDb;
use super::utils::{ProgressIndicator, copy_with_progress, HumanDuration};
use super::{Result, ResultExt, ErrorKind};

/// Helper for synching
pub struct SyncOptions {
    pub user_facing: bool,
}

/// The main memdb stash type
pub struct MemDbStash {
    path: PathBuf,
    s3: S3,
    local_state: RwLock<Option<Arc<SdkSyncState>>>,
    memdbs: RwLock<HashMap<SdkInfo, Arc<MemDb<'static>>>>,
}

/// Information about a remotely available SDK
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct RemoteSdk {
    filename: String,
    info: SdkInfo,
    size: u64,
    etag: String,
}

#[derive(Serialize, Deserialize, Default, Debug, Clone)]
struct SdkSyncState {
    sdks: HashMap<String, RemoteSdk>,
    revision: Option<u64>,
}

/// Information about the health of the stash sync
#[derive(Debug)]
pub struct SyncStatus {
    remote_total: u32,
    missing: u32,
    different: u32,
    revision: u64,
}

impl RemoteSdk {
    /// Creates a remote SDK object from some information
    pub fn new(filename: String, info: SdkInfo, etag: String, size: u64) -> RemoteSdk {
        RemoteSdk {
            filename: filename,
            info: info,
            etag: etag,
            size: size,
        }
    }

    /// The remotely visible filename for the SDK
    pub fn filename(&self) -> &str {
        &self.filename
    }

    /// The local filename the SDK has in the stash folder
    pub fn local_filename(&self) -> &str {
        self.filename.trim_right_matches('z')
    }

    /// The size of the SDK in bytes
    pub fn size(&self) -> u64 {
        self.size
    }

    /// Returns the SDK info
    pub fn info(&self) -> &SdkInfo {
        &self.info
    }
}

/// Iterator over the SDKs
pub type RemoteSdkIter<'a> = HashMapValuesIter<'a, String, RemoteSdk>;

impl SdkSyncState {
    pub fn get_sdk(&self, filename: &str) -> Option<&RemoteSdk> {
        self.sdks.get(filename)
    }

    pub fn update_sdk(&mut self, sdk: &RemoteSdk) {
        self.sdks.insert(sdk.local_filename().to_string(), sdk.clone());
    }

    pub fn sdks<'a>(&'a self) -> RemoteSdkIter<'a> {
        self.sdks.values()
    }
}

impl SyncStatus {

    /// Returns the lag (number of SDKs behind upstream)
    pub fn lag(&self) -> u32 {
        self.missing + self.different
    }

    /// Returns true if the local sync is still considered healthy
    pub fn is_healthy(&self) -> bool {
        let total = self.remote_total as f32;
        let lag = self.lag() as f32;
        lag / total < 0.10
    }

    /// Returns the revision of the stash
    pub fn revision(&self) -> u64 {
        self.revision
    }
}

impl Default for SyncOptions {
    fn default() -> SyncOptions {
        SyncOptions {
            user_facing: false,
        }
    }
}

impl MemDbStash {
    /// Opens a stash for a given config.
    pub fn new(config: &Config) -> Result<MemDbStash> {
        Ok(MemDbStash {
            path: config.get_symbol_dir()?.to_path_buf(),
            s3: S3::from_config(config)?,
            local_state: RwLock::new(None),
            memdbs: RwLock::new(HashMap::new()),
        })
    }

    fn get_local_sync_state_filename(&self) -> PathBuf {
        self.path.join("sync.state")
    }

    fn save_state(&self, new_state: &SdkSyncState, filename: &Path) -> Result<()> {
        let mut tmp_filename = filename.to_path_buf();
        tmp_filename.set_extension("tempstate");
        {
            let mut f = fs::File::create(&tmp_filename)?;
            serde_json::to_writer(&mut f, new_state)
                .chain_err(|| "Could not update sync state")?;
        }
        fs::rename(&tmp_filename, &filename)?;
        Ok(())
    }

    fn read_local_state(&self) -> Result<SdkSyncState> {
        let rv: SdkSyncState = match fs::File::open(&self.get_local_sync_state_filename()) {
            Ok(f) => serde_json::from_reader(io::BufReader::new(f))
                .chain_err(|| "Parsing error on loading sync state")?,
            Err(err) => {
                if err.kind() == io::ErrorKind::NotFound {
                    Default::default()
                } else {
                    return Err(err).chain_err(|| "Error loading sync state");
                }
            }
        };
        let mut opt = self.local_state.write().unwrap();
        *opt = Some(Arc::new(rv.clone()));
        Ok(rv)
    }

    fn get_local_state(&self) -> Result<Arc<SdkSyncState>> {
        if let Some(ref arc) = *self.local_state.read().unwrap() {
            return Ok(arc.clone());
        }
        self.read_local_state()?;
        Ok(self.local_state.read().unwrap().as_ref().unwrap().clone())
    }

    fn save_local_state(&self, new_state: &SdkSyncState) -> Result<()> {
        self.save_state(new_state, &self.get_local_sync_state_filename())?;
        let mut opt = self.local_state.write().unwrap();
        *opt = Some(Arc::new(new_state.clone()));
        Ok(())
    }

    fn fetch_remote_state(&self) -> Result<SdkSyncState> {
        let mut sdks = HashMap::new();
        for remote_sdk in self.s3.list_upstream_sdks()? {
            sdks.insert(remote_sdk.local_filename().into(), remote_sdk);
        }
        Ok(SdkSyncState { sdks: sdks, revision: None })
    }

    fn update_sdk(&self, sdk: &RemoteSdk, options: &SyncOptions) -> Result<()> {
        // XXX: the progress bar here can stall out because we currently
        // need to buffer the download into memory in the s3 code :(
        let progress = if options.user_facing {
            ProgressIndicator::new(sdk.size() as usize)
        } else {
            info!("updating {}", sdk.info());
            ProgressIndicator::disabled()
        };
        let started = UTC::now();
        progress.set_message(&format!("Synchronizing {}", sdk.info()));
        let mut src = self.s3.download_sdk(sdk)?;
        let dst = fs::File::create(self.path.join(sdk.local_filename()))?;
        let mut dst = XzDecoder::new(dst);
        copy_with_progress(&progress, &mut src, &mut dst)?;
        progress.finish(&format!("Synchronized {}", sdk.info()));

        let duration = UTC::now() - started;
        if !options.user_facing {
            info!("updated {} in {}", sdk.info(), HumanDuration(duration));
        }
        Ok(())
    }

    fn remove_sdk(&self, sdk: &RemoteSdk, options: &SyncOptions) -> Result<()> {
        if options.user_facing {
            info!("  Deleting {}", sdk.info());
        } else {
            info!("removing {}", sdk.info());
        }
        if let Err(err) = fs::remove_file(self.path.join(sdk.local_filename())) {
            if err.kind() != io::ErrorKind::NotFound {
                return Err(err.into());
            }
        }
        Ok(())
    }

    /// Returns the current revision
    pub fn get_revision(&self) -> Result<u64> {
        Ok(self.read_local_state()?.revision.unwrap_or(0))
    }

    /// Checks the local stash against the server
    pub fn get_sync_status(&self) -> Result<SyncStatus> {
        let local_state = self.read_local_state()?;
        let remote_state = self.fetch_remote_state()?;

        let mut remote_total = 0;
        let mut missing = 0;
        let mut different = 0;

        for sdk in remote_state.sdks() {
            if let Some(local_sdk) = local_state.get_sdk(sdk.local_filename()) {
                if local_sdk != sdk {
                    different += 1;
                }
            } else {
                missing += 1;
            }
            remote_total += 1;
        }

        Ok(SyncStatus {
            remote_total: remote_total as u32,
            missing: missing as u32,
            different: different as u32,
            revision: local_state.revision.unwrap_or(0),
        })
    }

    /// Synchronize the local stash with the server
    pub fn sync(&self, options: SyncOptions) -> Result<()> {
        let mut local_state = self.read_local_state()?;
        let mut remote_state = self.fetch_remote_state()?;
        let started = UTC::now();
        let mut changed = false;

        let mut to_delete : HashSet<_> = HashSet::from_iter(
            local_state.sdks().map(|x| x.local_filename().to_string()));

        for sdk in remote_state.sdks() {
            let mut changed_something = false;
            if let Some(local_sdk) = local_state.get_sdk(sdk.local_filename()) {
                if local_sdk != sdk {
                    self.update_sdk(&sdk, &options)?;
                    changed_something = true;
                } else if options.user_facing {
                    println!("  ⸰ Unchanged {}", sdk.info());
                } else {
                    debug!("unchanged sdk {}", sdk.info());
                }
            } else {
                self.update_sdk(&sdk, &options)?;
                changed_something = true;
            }

            to_delete.remove(sdk.local_filename());
            if changed_something {
                changed = true;
                local_state.update_sdk(&sdk);
                local_state.revision = Some(local_state.revision.unwrap_or(0) + 1);
                self.save_local_state(&local_state)?;
            }
        }

        for local_filename in to_delete.iter() {
            if let Some(sdk) = local_state.get_sdk(local_filename) {
                self.remove_sdk(sdk, &options)?;
            }
        }

        let duration = UTC::now() - started;
        if options.user_facing {
            println!("Sync done in {}", HumanDuration(duration));
        } else if changed {
            info!("finished sync in {}", HumanDuration(duration));
        }

        // if we get this far, the remote state is indeed the local state.
        remote_state.revision = Some(local_state.revision.unwrap_or(0) + 1);
        self.save_local_state(&remote_state)?;

        Ok(())
    }

    /// Looks up an memdb by an SDK info if it's available.
    ///
    /// This returns a memdb wrapped in an arc as internally the system
    /// might try to unload the memdb if no longer needed.  If the MemDb
    /// does not exist, a `UnknownSdk` error is returned.
    pub fn get_memdb(&self, info: &SdkInfo) -> Result<Arc<MemDb<'static>>> {
        let local_state = self.get_local_state()?;
        let filename = info.memdb_filename();

        // make sure we check in the local state first if the SDK exists.
        // if we go directly to the memdbs array or look at the file system
        // we might start to consider things that are not available yet or
        // not available any longer.
        if local_state.get_sdk(&filename).is_some() {
            if let Some(arc) = self.memdbs.read().unwrap().get(info) {
                return Ok(arc.clone());
            }
            let memdb = MemDb::from_path(self.path.join(&filename))?;
            self.memdbs.write().unwrap().insert(info.clone(), Arc::new(memdb));
            if let Some(arc) = self.memdbs.read().unwrap().get(info) {
                return Ok(arc.clone());
            }
        }

        Err(ErrorKind::UnknownSdk.into())
    }

    /// Looks up an memdb by an SDK info as string if available.
    pub fn get_memdb_from_sdk_id(&self, sdk_id: &str) -> Result<Arc<MemDb<'static>>> {
        if let Some(sdk_info) = SdkInfo::from_filename(sdk_id) {
            self.get_memdb(&sdk_info)
        } else {
            Err(ErrorKind::UnknownSdk.into())
        }
    }

    /// Given an SDK info this returns an array of fuzzy matches for it.
    pub fn fuzzy_match_sdk_id(&self, sdk_id: &str) -> Result<Vec<SdkInfo>> {
        let local_state = self.get_local_state()?;
        let mut rv = vec![];

        if let Some(sdk_info) = SdkInfo::from_filename(sdk_id) {
            // find all sdks that have a fuzzy match
            for other in local_state.sdks() {
                if let Some(quality) = other.info().get_fuzzy_match(&sdk_info) {
                    rv.push((quality, other.info().clone()));
                }
            }
        }

        rv.sort_by_key(|&(q, _)| q);

        Ok(rv.into_iter().map(|(_, info)| info).collect())
    }
}
<commit_msg>Optimize memdb lookup from stash<commit_after>//! Provide access to locally cached memdb SDKs
//!
//! The `MemDbStash` pulls in remote SDKs from an S3 bucket and provides
//! access to it.  This is used by the symbol server to manage the local
//! cache and also to refer to memdb files that are mmap'ed in.
use std::fs;
use std::io;
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Values as HashMapValuesIter;
use std::sync::{Arc, RwLock};

use serde_json;
use xz2::write::XzDecoder;
use chrono::UTC;

use super::config::Config;
use super::sdk::SdkInfo;
use super::s3::S3;
use super::memdb::MemDb;
use super::utils::{ProgressIndicator, copy_with_progress, HumanDuration};
use super::{Result, ResultExt, ErrorKind};

/// Helper for synching
pub struct SyncOptions {
    pub user_facing: bool,
}

/// The main memdb stash type
pub struct MemDbStash {
    path: PathBuf,
    s3: S3,
    local_state: RwLock<Option<Arc<SdkSyncState>>>,
    memdbs: RwLock<HashMap<SdkInfo, Arc<MemDb<'static>>>>,
}

/// Information about a remotely available SDK
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct RemoteSdk {
    filename: String,
    info: SdkInfo,
    size: u64,
    etag: String,
}

#[derive(Serialize, Deserialize, Default, Debug, Clone)]
struct SdkSyncState {
    sdks: HashMap<String, RemoteSdk>,
    revision: Option<u64>,
}

/// Information about the health of the stash sync
#[derive(Debug)]
pub struct SyncStatus {
    remote_total: u32,
    missing: u32,
    different: u32,
    revision: u64,
}

impl RemoteSdk {
    /// Creates a remote SDK object from some information
    pub fn new(filename: String, info: SdkInfo, etag: String, size: u64) -> RemoteSdk {
        RemoteSdk {
            filename: filename,
            info: info,
            etag: etag,
            size: size,
        }
    }

    /// The remotely visible filename for the SDK
    pub fn filename(&self) -> &str {
        &self.filename
    }

    /// The local filename the SDK has in the stash folder
    pub fn local_filename(&self) -> &str {
        self.filename.trim_right_matches('z')
    }

    /// The size of the SDK in bytes
    pub fn size(&self) -> u64 {
        self.size
    }

    /// Returns the SDK info
    pub fn info(&self) -> &SdkInfo {
        &self.info
    }
}

/// Iterator over the SDKs
pub type RemoteSdkIter<'a> = HashMapValuesIter<'a, String, RemoteSdk>;

impl SdkSyncState {
    pub fn get_sdk(&self, filename: &str) -> Option<&RemoteSdk> {
        self.sdks.get(filename)
    }

    pub fn update_sdk(&mut self, sdk: &RemoteSdk) {
        self.sdks.insert(sdk.local_filename().to_string(), sdk.clone());
    }

    pub fn sdks<'a>(&'a self) -> RemoteSdkIter<'a> {
        self.sdks.values()
    }
}

impl SyncStatus {

    /// Returns the lag (number of SDKs behind upstream)
    pub fn lag(&self) -> u32 {
        self.missing + self.different
    }

    /// Returns true if the local sync is still considered healthy
    pub fn is_healthy(&self) -> bool {
        let total = self.remote_total as f32;
        let lag = self.lag() as f32;
        lag / total < 0.10
    }

    /// Returns the revision of the stash
    pub fn revision(&self) -> u64 {
        self.revision
    }
}

impl Default for SyncOptions {
    fn default() -> SyncOptions {
        SyncOptions {
            user_facing: false,
        }
    }
}

impl MemDbStash {
    /// Opens a stash for a given config.
    pub fn new(config: &Config) -> Result<MemDbStash> {
        Ok(MemDbStash {
            path: config.get_symbol_dir()?.to_path_buf(),
            s3: S3::from_config(config)?,
            local_state: RwLock::new(None),
            memdbs: RwLock::new(HashMap::new()),
        })
    }

    fn get_local_sync_state_filename(&self) -> PathBuf {
        self.path.join("sync.state")
    }

    fn save_state(&self, new_state: &SdkSyncState, filename: &Path) -> Result<()> {
        let mut tmp_filename = filename.to_path_buf();
        tmp_filename.set_extension("tempstate");
        {
            let mut f = fs::File::create(&tmp_filename)?;
            serde_json::to_writer(&mut f, new_state)
                .chain_err(|| "Could not update sync state")?;
        }
        fs::rename(&tmp_filename, &filename)?;
        Ok(())
    }

    fn read_local_state(&self) -> Result<SdkSyncState> {
        let rv: SdkSyncState = match fs::File::open(&self.get_local_sync_state_filename()) {
            Ok(f) => serde_json::from_reader(io::BufReader::new(f))
                .chain_err(|| "Parsing error on loading sync state")?,
            Err(err) => {
                if err.kind() == io::ErrorKind::NotFound {
                    Default::default()
                } else {
                    return Err(err).chain_err(|| "Error loading sync state");
                }
            }
        };
        let mut opt = self.local_state.write().unwrap();
        *opt = Some(Arc::new(rv.clone()));
        Ok(rv)
    }

    fn get_local_state(&self) -> Result<Arc<SdkSyncState>> {
        if let Some(ref arc) = *self.local_state.read().unwrap() {
            return Ok(arc.clone());
        }
        self.read_local_state()?;
        Ok(self.local_state.read().unwrap().as_ref().unwrap().clone())
    }

    fn save_local_state(&self, new_state: &SdkSyncState) -> Result<()> {
        self.save_state(new_state, &self.get_local_sync_state_filename())?;
        let mut opt = self.local_state.write().unwrap();
        *opt = Some(Arc::new(new_state.clone()));
        Ok(())
    }

    fn fetch_remote_state(&self) -> Result<SdkSyncState> {
        let mut sdks = HashMap::new();
        for remote_sdk in self.s3.list_upstream_sdks()? {
            sdks.insert(remote_sdk.local_filename().into(), remote_sdk);
        }
        Ok(SdkSyncState { sdks: sdks, revision: None })
    }

    fn update_sdk(&self, sdk: &RemoteSdk, options: &SyncOptions) -> Result<()> {
        // XXX: the progress bar here can stall out because we currently
        // need to buffer the download into memory in the s3 code :(
        let progress = if options.user_facing {
            ProgressIndicator::new(sdk.size() as usize)
        } else {
            info!("updating {}", sdk.info());
            ProgressIndicator::disabled()
        };
        let started = UTC::now();
        progress.set_message(&format!("Synchronizing {}", sdk.info()));
        let mut src = self.s3.download_sdk(sdk)?;
        let dst = fs::File::create(self.path.join(sdk.local_filename()))?;
        let mut dst = XzDecoder::new(dst);
        copy_with_progress(&progress, &mut src, &mut dst)?;
        progress.finish(&format!("Synchronized {}", sdk.info()));

        let duration = UTC::now() - started;
        if !options.user_facing {
            info!("updated {} in {}", sdk.info(), HumanDuration(duration));
        }
        Ok(())
    }

    fn remove_sdk(&self, sdk: &RemoteSdk, options: &SyncOptions) -> Result<()> {
        if options.user_facing {
            info!("  Deleting {}", sdk.info());
        } else {
            info!("removing {}", sdk.info());
        }
        if let Err(err) = fs::remove_file(self.path.join(sdk.local_filename())) {
            if err.kind() != io::ErrorKind::NotFound {
                return Err(err.into());
            }
        }
        Ok(())
    }

    /// Returns the current revision
    pub fn get_revision(&self) -> Result<u64> {
        Ok(self.read_local_state()?.revision.unwrap_or(0))
    }

    /// Checks the local stash against the server
    pub fn get_sync_status(&self) -> Result<SyncStatus> {
        let local_state = self.read_local_state()?;
        let remote_state = self.fetch_remote_state()?;

        let mut remote_total = 0;
        let mut missing = 0;
        let mut different = 0;

        for sdk in remote_state.sdks() {
            if let Some(local_sdk) = local_state.get_sdk(sdk.local_filename()) {
                if local_sdk != sdk {
                    different += 1;
                }
            } else {
                missing += 1;
            }
            remote_total += 1;
        }

        Ok(SyncStatus {
            remote_total: remote_total as u32,
            missing: missing as u32,
            different: different as u32,
            revision: local_state.revision.unwrap_or(0),
        })
    }

    /// Synchronize the local stash with the server
    pub fn sync(&self, options: SyncOptions) -> Result<()> {
        let mut local_state = self.read_local_state()?;
        let mut remote_state = self.fetch_remote_state()?;
        let started = UTC::now();
        let mut changed = false;

        let mut to_delete : HashSet<_> = HashSet::from_iter(
            local_state.sdks().map(|x| x.local_filename().to_string()));

        for sdk in remote_state.sdks() {
            let mut changed_something = false;
            if let Some(local_sdk) = local_state.get_sdk(sdk.local_filename()) {
                if local_sdk != sdk {
                    self.update_sdk(&sdk, &options)?;
                    changed_something = true;
                } else if options.user_facing {
                    println!("  ⸰ Unchanged {}", sdk.info());
                } else {
                    debug!("unchanged sdk {}", sdk.info());
                }
            } else {
                self.update_sdk(&sdk, &options)?;
                changed_something = true;
            }

            to_delete.remove(sdk.local_filename());
            if changed_something {
                changed = true;
                local_state.update_sdk(&sdk);
                local_state.revision = Some(local_state.revision.unwrap_or(0) + 1);
                self.save_local_state(&local_state)?;
            }
        }

        for local_filename in to_delete.iter() {
            if let Some(sdk) = local_state.get_sdk(local_filename) {
                self.remove_sdk(sdk, &options)?;
                self.memdbs.write().unwrap().remove(&sdk.info());
            }
        }

        let duration = UTC::now() - started;
        if options.user_facing {
            println!("Sync done in {}", HumanDuration(duration));
        } else if changed {
            info!("finished sync in {}", HumanDuration(duration));
        }

        // if we get this far, the remote state is indeed the local state.
        remote_state.revision = Some(local_state.revision.unwrap_or(0) + 1);
        self.save_local_state(&remote_state)?;

        Ok(())
    }

    /// Looks up an memdb by an SDK info if it's available.
    ///
    /// This returns a memdb wrapped in an arc as internally the system
    /// might try to unload the memdb if no longer needed.  If the MemDb
    /// does not exist, a `UnknownSdk` error is returned.
    pub fn get_memdb(&self, info: &SdkInfo) -> Result<Arc<MemDb<'static>>> {
        // try to fetch it from the local mapping.  The sync method will
        // remove it from here automatically.
        if let Some(arc) = self.memdbs.read().unwrap().get(info) {
            return Ok(arc.clone());
        }

        let local_state = self.get_local_state()?;
        let filename = info.memdb_filename();

        // make sure we check in the local state first if the SDK exists.
        // if we go directly to the memdbs array or look at the file system
        // we might start to consider things that are not available yet or
        // not available any longer.
        if local_state.get_sdk(&filename).is_some() {
            let memdb = MemDb::from_path(self.path.join(&filename))?;
            self.memdbs.write().unwrap().insert(info.clone(), Arc::new(memdb));
            if let Some(arc) = self.memdbs.read().unwrap().get(info) {
                return Ok(arc.clone());
            }
        }

        Err(ErrorKind::UnknownSdk.into())
    }

    /// Looks up an memdb by an SDK info as string if available.
    pub fn get_memdb_from_sdk_id(&self, sdk_id: &str) -> Result<Arc<MemDb<'static>>> {
        if let Some(sdk_info) = SdkInfo::from_filename(sdk_id) {
            self.get_memdb(&sdk_info)
        } else {
            Err(ErrorKind::UnknownSdk.into())
        }
    }

    /// Given an SDK info this returns an array of fuzzy matches for it.
    pub fn fuzzy_match_sdk_id(&self, sdk_id: &str) -> Result<Vec<SdkInfo>> {
        let local_state = self.get_local_state()?;
        let mut rv = vec![];

        if let Some(sdk_info) = SdkInfo::from_filename(sdk_id) {
            // find all sdks that have a fuzzy match
            for other in local_state.sdks() {
                if let Some(quality) = other.info().get_fuzzy_match(&sdk_info) {
                    rv.push((quality, other.info().clone()));
                }
            }
        }

        rv.sort_by_key(|&(q, _)| q);

        Ok(rv.into_iter().map(|(_, info)| info).collect())
    }
}
<|endoftext|>


<commit_before>#[test]
use core::num::{One};
#[test]
use core::rand::{random};
#[test]
use std::cmp::FuzzyEq;
// #[test]
// use ndim::nmat::NMat;
#[test]
use traits::inv::Inv;
#[test]
use dim1::mat1::Mat1;
#[test]
use dim2::mat2::Mat2;
#[test]
use dim3::mat3::Mat3;
// #[test]
// use traits::dim::d7;

// FIXME: this one fails with an ICE: node_id_to_type: no type for node [...]
// #[test]
// fn test_inv_nmat()
// {
//   let randmat : NMat<d7, f64> = random();
//
//   assert!((randmat.inverse() * randmat).fuzzy_eq(&One::one()));
// }

#[test]
fn test_inv_mat1()
{
  for uint::range(0u, 10000u) |_|
  {
    let randmat : Mat1<f64> = random();

    assert!((randmat.inverse() * randmat).fuzzy_eq(&One::one()));
  }
}

#[test]
fn test_inv_mat2()
{
  for uint::range(0u, 10000u) |_|
  {
    let randmat : Mat2<f64> = random();

    assert!((randmat.inverse() * randmat).fuzzy_eq(&One::one()));
  }
}

#[test]
fn test_inv_mat3()
{
  for uint::range(0u, 10000u) |_|
  {
    let randmat : Mat3<f64> = random();

    assert!((randmat.inverse() * randmat).fuzzy_eq(&One::one()));
  }
}

#[test]
fn test_rot2()
{
}
<commit_msg>Add a test for the 2d rotation.<commit_after>#[test]
use core::num::{One, abs};
#[test]
use core::rand::{random};
#[test]
use std::cmp::FuzzyEq;
// #[test]
// use ndim::nmat::NMat;
#[test]
use traits::inv::Inv;
#[test]
use traits::rotation::Rotation;
#[test]
use dim1::vec1::vec1;
#[test]
use dim1::mat1::Mat1;
#[test]
use dim2::mat2::Mat2;
#[test]
use dim3::mat3::Mat3;
#[test]
use adaptors::rotmat::Rotmat;
// #[test]
// use traits::dim::d7;

// FIXME: this one fails with an ICE: node_id_to_type: no type for node [...]
// #[test]
// fn test_inv_nmat()
// {
//   let randmat : NMat<d7, f64> = random();
//
//   assert!((randmat.inverse() * randmat).fuzzy_eq(&One::one()));
// }

#[test]
fn test_inv_mat1()
{
  for uint::range(0u, 10000u) |_|
  {
    let randmat : Mat1<f64> = random();

    assert!((randmat.inverse() * randmat).fuzzy_eq(&One::one()));
  }
}

#[test]
fn test_inv_mat2()
{
  for uint::range(0u, 10000u) |_|
  {
    let randmat : Mat2<f64> = random();

    assert!((randmat.inverse() * randmat).fuzzy_eq(&One::one()));
  }
}

#[test]
fn test_inv_mat3()
{
  for uint::range(0u, 10000u) |_|
  {
    let randmat : Mat3<f64> = random();

    assert!((randmat.inverse() * randmat).fuzzy_eq(&One::one()));
  }
}

#[test]
fn test_rotation2()
{
  for uint::range(0u, 10000u) |_|
  {
    let randmat = One::one::<Rotmat<Mat2<f64>>>();
    let ang     = &vec1(abs::<f64>(random()) % f64::consts::pi);

    assert!(randmat.rotated(ang).rotation().fuzzy_eq(ang));
  }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::iter::Map;
use std::slice::Iter;

use regex::Regex;

type SliceVec = Vec<(usize, usize)>;

#[derive(Debug)]
pub enum Pattern {
    Template
}

impl fmt::Display for Pattern {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let result = match *self {
            Pattern::Template => r"(\{%.*?%\}|\{\{.*?\}\}?|\{\{|\{%)"
        };

        write!(f, "{}", result)
    }
}

impl Pattern {
    pub fn to_regex(&self) -> Regex {
        let pattern = format!("{}", self);
        Regex::new(&pattern).unwrap()
    }
}

pub struct Tokenizer<'t> {
    source: &'t str
}

impl<'t> Tokenizer<'t> {
    pub fn new<'a>(source: &'a str) -> Tokenizer<'a> {
        Tokenizer { source: source }
    }

    pub fn tokenize<'a>(&'a self, pattern: &'a Regex) -> Vec<&'a str> {
        let slices = self.matched_slices(pattern);
        slices.iter().map(|&(start, end)| &self.source[start..end]).collect()
    }

    fn matched_slices(&self, pattern: &Regex) -> SliceVec {
        let mut slices = pattern.find_iter(self.source).collect::<Vec<_>>();
        let missing = self.find_missing_slices(&slices);

        slices.extend(&missing);
        slices.sort();
        slices
    }

    fn find_missing_slices(&self, slices: &SliceVec) -> SliceVec {
        if slices.is_empty() { return vec![(0, self.source.len())]; }

        let mut missing = self.missing_middle_slices(slices);

        if let Some(first) = self.missing_first_slice(slices) {
            missing.push(first);
        }

        if let Some(last) = self.missing_last_slice(slices) {
            missing.push(last);
        }

        missing
    }

    fn missing_first_slice(&self, slices: &SliceVec) -> Option<(usize, usize)> {
        let pos = slices[0].0;
        if pos == 0 { return None; }

        Some((0, pos))
    }

    fn missing_last_slice(&self, slices: &SliceVec) -> Option<(usize, usize)> {
        let last = slices.last().unwrap();
        let len  = self.source.len();
        if last.1 == len { return None; }

        Some((last.1, len))
    }

    fn missing_middle_slices(&self, slices: &SliceVec) -> SliceVec {
        let mut missing: SliceVec = Vec::new();
        let last_index            = slices.len() - 1;

        for (index, &(_, right)) in slices.iter().enumerate() {
            if index == last_index { continue; }

            let edge = slices[index + 1].0;
            if right != edge {
                missing.push((right, edge));
            }
        }

        missing
    }
}

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

    fn assert_tokens(tokenizer: &Tokenizer, expected: Vec<&str>) {
        let re     = Pattern::Template.to_regex();
        let actual = tokenizer.tokenize(&re);

        assert_eq!(expected, actual);
    }

    #[test]
    fn tokenize_blank_string() {
        let tokenizer = Tokenizer::new("");
        assert_tokens(&tokenizer, vec![""]);
    }

    #[test]
    fn tokenize_whitespace_only_string() {
        let tokenizer = Tokenizer::new("  ");
        assert_tokens(&tokenizer, vec!["  "]);
    }

    #[test]
    fn tokenize_string_with_no_matches() {
        let tokenizer = Tokenizer::new("hello world");
        assert_tokens(&tokenizer, vec!["hello world"]);
    }

    #[test]
    fn tokenize_single_variable() {
        let tokenizer = Tokenizer::new("{{funk}}");
        assert_tokens(&tokenizer, vec!["{{funk}}"]);
    }

    #[test]
    fn tokenize_single_variable_surrounded_by_whitespace() {
        let tokenizer = Tokenizer::new(" {{funk}} ");
        assert_tokens(&tokenizer, vec![" ", "{{funk}}", " "]);
    }

    #[test]
    fn tokenize_multiple_variables() {
        let tokenizer = Tokenizer::new(" {{funk}} {{so}} {{brutha}} ");
        let expected = vec![
            " ",
            "{{funk}}",
            " ",
            "{{so}}",
            " ",
            "{{brutha}}",
            " "
        ];

        assert_tokens(&tokenizer, expected);
    }

    #[test]
    fn tokenize_single_block() {
        let tokenizer = Tokenizer::new(" {%comment%} ");
        assert_tokens(&tokenizer, vec![" ", "{%comment%}", " "]);
    }

    #[test]
    fn tokenize_empty_block_tag() {
        let tokenizer = Tokenizer::new(" {% thing %} {% comment %} My comment here {% endcomment %} ");

        assert_tokens(&tokenizer, vec![
            " ",
            "{% thing %}",
            " ",
            "{% comment %}",
            " My comment here ",
            "{% endcomment %}",
            " "
        ]);
    }

    #[test]
    fn tokenize_multiline_string() {
        let tokenizer = Tokenizer::new("{%comment%}\nMy Comment\n{%endcomment%}\n");

        assert_tokens(&tokenizer, vec![
            "{%comment%}",
            "\nMy Comment\n",
            "{%endcomment%}",
            "\n"
        ]);
    }

    #[test]
    fn tokenize_html_with_liquid() {
        let content = r#"

    <title>{{ title }}</title>

{% comment %}Content here{% endcomment %}

        "#;

        let tokenizer = Tokenizer::new(&content);
        assert_tokens(&tokenizer, vec![
            "\n\n  \n    <title>",
            "{{ title }}",
            "</title>\n  \n  \n
",
            "{% comment %}",
            "Content here",
            "{% endcomment %}",
            "
\n    \n  \n\n        "
        ]);
    }
}
<commit_msg>removing dead use module statements<commit_after>use std::fmt;

use regex::Regex;

type SliceVec = Vec<(usize, usize)>;

#[derive(Debug)]
pub enum Pattern {
    Template
}

impl fmt::Display for Pattern {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let result = match *self {
            Pattern::Template => r"(\{%.*?%\}|\{\{.*?\}\}?|\{\{|\{%)"
        };

        write!(f, "{}", result)
    }
}

impl Pattern {
    pub fn to_regex(&self) -> Regex {
        let pattern = format!("{}", self);
        Regex::new(&pattern).unwrap()
    }
}

pub struct Tokenizer<'t> {
    source: &'t str
}

impl<'t> Tokenizer<'t> {
    pub fn new<'a>(source: &'a str) -> Tokenizer<'a> {
        Tokenizer { source: source }
    }

    pub fn tokenize<'a>(&'a self, pattern: &'a Regex) -> Vec<&'a str> {
        let slices = self.matched_slices(pattern);
        slices.iter().map(|&(start, end)| &self.source[start..end]).collect()
    }

    fn matched_slices(&self, pattern: &Regex) -> SliceVec {
        let mut slices = pattern.find_iter(self.source).collect::<Vec<_>>();
        let missing = self.find_missing_slices(&slices);

        slices.extend(&missing);
        slices.sort();
        slices
    }

    fn find_missing_slices(&self, slices: &SliceVec) -> SliceVec {
        if slices.is_empty() { return vec![(0, self.source.len())]; }

        let mut missing = self.missing_middle_slices(slices);

        if let Some(first) = self.missing_first_slice(slices) {
            missing.push(first);
        }

        if let Some(last) = self.missing_last_slice(slices) {
            missing.push(last);
        }

        missing
    }

    fn missing_first_slice(&self, slices: &SliceVec) -> Option<(usize, usize)> {
        let pos = slices[0].0;
        if pos == 0 { return None; }

        Some((0, pos))
    }

    fn missing_last_slice(&self, slices: &SliceVec) -> Option<(usize, usize)> {
        let last = slices.last().unwrap();
        let len  = self.source.len();
        if last.1 == len { return None; }

        Some((last.1, len))
    }

    fn missing_middle_slices(&self, slices: &SliceVec) -> SliceVec {
        let mut missing: SliceVec = Vec::new();
        let last_index            = slices.len() - 1;

        for (index, &(_, right)) in slices.iter().enumerate() {
            if index == last_index { continue; }

            let edge = slices[index + 1].0;
            if right != edge {
                missing.push((right, edge));
            }
        }

        missing
    }
}

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

    fn assert_tokens(tokenizer: &Tokenizer, expected: Vec<&str>) {
        let re     = Pattern::Template.to_regex();
        let actual = tokenizer.tokenize(&re);

        assert_eq!(expected, actual);
    }

    #[test]
    fn tokenize_blank_string() {
        let tokenizer = Tokenizer::new("");
        assert_tokens(&tokenizer, vec![""]);
    }

    #[test]
    fn tokenize_whitespace_only_string() {
        let tokenizer = Tokenizer::new("  ");
        assert_tokens(&tokenizer, vec!["  "]);
    }

    #[test]
    fn tokenize_string_with_no_matches() {
        let tokenizer = Tokenizer::new("hello world");
        assert_tokens(&tokenizer, vec!["hello world"]);
    }

    #[test]
    fn tokenize_single_variable() {
        let tokenizer = Tokenizer::new("{{funk}}");
        assert_tokens(&tokenizer, vec!["{{funk}}"]);
    }

    #[test]
    fn tokenize_single_variable_surrounded_by_whitespace() {
        let tokenizer = Tokenizer::new(" {{funk}} ");
        assert_tokens(&tokenizer, vec![" ", "{{funk}}", " "]);
    }

    #[test]
    fn tokenize_multiple_variables() {
        let tokenizer = Tokenizer::new(" {{funk}} {{so}} {{brutha}} ");
        let expected = vec![
            " ",
            "{{funk}}",
            " ",
            "{{so}}",
            " ",
            "{{brutha}}",
            " "
        ];

        assert_tokens(&tokenizer, expected);
    }

    #[test]
    fn tokenize_single_block() {
        let tokenizer = Tokenizer::new(" {%comment%} ");
        assert_tokens(&tokenizer, vec![" ", "{%comment%}", " "]);
    }

    #[test]
    fn tokenize_empty_block_tag() {
        let tokenizer = Tokenizer::new(" {% thing %} {% comment %} My comment here {% endcomment %} ");

        assert_tokens(&tokenizer, vec![
            " ",
            "{% thing %}",
            " ",
            "{% comment %}",
            " My comment here ",
            "{% endcomment %}",
            " "
        ]);
    }

    #[test]
    fn tokenize_multiline_string() {
        let tokenizer = Tokenizer::new("{%comment%}\nMy Comment\n{%endcomment%}\n");

        assert_tokens(&tokenizer, vec![
            "{%comment%}",
            "\nMy Comment\n",
            "{%endcomment%}",
            "\n"
        ]);
    }

    #[test]
    fn tokenize_html_with_liquid() {
        let content = r#"

    <title>{{ title }}</title>

{% comment %}Content here{% endcomment %}

        "#;

        let tokenizer = Tokenizer::new(&content);
        assert_tokens(&tokenizer, vec![
            "\n\n  \n    <title>",
            "{{ title }}",
            "</title>\n  \n  \n
",
            "{% comment %}",
            "Content here",
            "{% endcomment %}",
            "
\n    \n  \n\n        "
        ]);
    }
}
<|endoftext|>


<commit_before>//! Locating various executables part of a C toolchain.

use std::path::PathBuf;

use rustc_middle::bug;
use rustc_session::Session;
use rustc_target::spec::LinkerFlavor;

/// Tries to infer the path of a binary for the target toolchain from the linker name.
pub(crate) fn get_toolchain_binary(sess: &Session, tool: &str) -> PathBuf {
    let (mut linker, _linker_flavor) = linker_and_flavor(sess);
    let linker_file_name = linker
        .file_name()
        .and_then(|name| name.to_str())
        .unwrap_or_else(|| sess.fatal("couldn't extract file name from specified linker"));

    if linker_file_name == "ld.lld" {
        if tool != "ld" {
            linker.set_file_name(tool)
        }
    } else {
        let tool_file_name = linker_file_name
            .replace("ld", tool)
            .replace("gcc", tool)
            .replace("clang", tool)
            .replace("cc", tool);

        linker.set_file_name(tool_file_name)
    }

    linker
}

// Adapted from https://github.com/rust-lang/rust/blob/5db778affee7c6600c8e7a177c48282dab3f6292/src/librustc_codegen_ssa/back/link.rs#L848-L931
fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
    fn infer_from(
        sess: &Session,
        linker: Option<PathBuf>,
        flavor: Option<LinkerFlavor>,
    ) -> Option<(PathBuf, LinkerFlavor)> {
        match (linker, flavor) {
            (Some(linker), Some(flavor)) => Some((linker, flavor)),
            // only the linker flavor is known; use the default linker for the selected flavor
            (None, Some(flavor)) => Some((
                PathBuf::from(match flavor {
                    LinkerFlavor::Em => {
                        if cfg!(windows) {
                            "emcc.bat"
                        } else {
                            "emcc"
                        }
                    }
                    LinkerFlavor::Gcc => {
                        if cfg!(any(target_os = "solaris", target_os = "illumos")) {
                            // On historical Solaris systems, "cc" may have
                            // been Sun Studio, which is not flag-compatible
                            // with "gcc".  This history casts a long shadow,
                            // and many modern illumos distributions today
                            // ship GCC as "gcc" without also making it
                            // available as "cc".
                            "gcc"
                        } else {
                            "cc"
                        }
                    }
                    LinkerFlavor::Ld => "ld",
                    LinkerFlavor::Msvc => "link.exe",
                    LinkerFlavor::Lld(_) => "lld",
                    LinkerFlavor::PtxLinker => "rust-ptx-linker",
                }),
                flavor,
            )),
            (Some(linker), None) => {
                let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
                    sess.fatal("couldn't extract file stem from specified linker")
                });

                let flavor = if stem == "emcc" {
                    LinkerFlavor::Em
                } else if stem == "gcc"
                    || stem.ends_with("-gcc")
                    || stem == "clang"
                    || stem.ends_with("-clang")
                {
                    LinkerFlavor::Gcc
                } else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
                    LinkerFlavor::Ld
                } else if stem == "link" || stem == "lld-link" {
                    LinkerFlavor::Msvc
                } else if stem == "lld" || stem == "rust-lld" {
                    LinkerFlavor::Lld(sess.target.lld_flavor)
                } else {
                    // fall back to the value in the target spec
                    sess.target.linker_flavor
                };

                Some((linker, flavor))
            }
            (None, None) => None,
        }
    }

    // linker and linker flavor specified via command line have precedence over what the target
    // specification specifies
    if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), sess.opts.cg.linker_flavor) {
        return ret;
    }

    if let Some(ret) = infer_from(
        sess,
        sess.target.linker.clone().map(PathBuf::from),
        Some(sess.target.linker_flavor),
    ) {
        return ret;
    }

    bug!("Not enough information provided to determine how to invoke the linker");
}
<commit_msg>Add BPF target<commit_after>//! Locating various executables part of a C toolchain.

use std::path::PathBuf;

use rustc_middle::bug;
use rustc_session::Session;
use rustc_target::spec::LinkerFlavor;

/// Tries to infer the path of a binary for the target toolchain from the linker name.
pub(crate) fn get_toolchain_binary(sess: &Session, tool: &str) -> PathBuf {
    let (mut linker, _linker_flavor) = linker_and_flavor(sess);
    let linker_file_name = linker
        .file_name()
        .and_then(|name| name.to_str())
        .unwrap_or_else(|| sess.fatal("couldn't extract file name from specified linker"));

    if linker_file_name == "ld.lld" {
        if tool != "ld" {
            linker.set_file_name(tool)
        }
    } else {
        let tool_file_name = linker_file_name
            .replace("ld", tool)
            .replace("gcc", tool)
            .replace("clang", tool)
            .replace("cc", tool);

        linker.set_file_name(tool_file_name)
    }

    linker
}

// Adapted from https://github.com/rust-lang/rust/blob/5db778affee7c6600c8e7a177c48282dab3f6292/src/librustc_codegen_ssa/back/link.rs#L848-L931
fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
    fn infer_from(
        sess: &Session,
        linker: Option<PathBuf>,
        flavor: Option<LinkerFlavor>,
    ) -> Option<(PathBuf, LinkerFlavor)> {
        match (linker, flavor) {
            (Some(linker), Some(flavor)) => Some((linker, flavor)),
            // only the linker flavor is known; use the default linker for the selected flavor
            (None, Some(flavor)) => Some((
                PathBuf::from(match flavor {
                    LinkerFlavor::Em => {
                        if cfg!(windows) {
                            "emcc.bat"
                        } else {
                            "emcc"
                        }
                    }
                    LinkerFlavor::Gcc => {
                        if cfg!(any(target_os = "solaris", target_os = "illumos")) {
                            // On historical Solaris systems, "cc" may have
                            // been Sun Studio, which is not flag-compatible
                            // with "gcc".  This history casts a long shadow,
                            // and many modern illumos distributions today
                            // ship GCC as "gcc" without also making it
                            // available as "cc".
                            "gcc"
                        } else {
                            "cc"
                        }
                    }
                    LinkerFlavor::Ld => "ld",
                    LinkerFlavor::Msvc => "link.exe",
                    LinkerFlavor::Lld(_) => "lld",
                    LinkerFlavor::PtxLinker => "rust-ptx-linker",
                    LinkerFlavor::BpfLinker => "bpf-linker",
                }),
                flavor,
            )),
            (Some(linker), None) => {
                let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
                    sess.fatal("couldn't extract file stem from specified linker")
                });

                let flavor = if stem == "emcc" {
                    LinkerFlavor::Em
                } else if stem == "gcc"
                    || stem.ends_with("-gcc")
                    || stem == "clang"
                    || stem.ends_with("-clang")
                {
                    LinkerFlavor::Gcc
                } else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
                    LinkerFlavor::Ld
                } else if stem == "link" || stem == "lld-link" {
                    LinkerFlavor::Msvc
                } else if stem == "lld" || stem == "rust-lld" {
                    LinkerFlavor::Lld(sess.target.lld_flavor)
                } else {
                    // fall back to the value in the target spec
                    sess.target.linker_flavor
                };

                Some((linker, flavor))
            }
            (None, None) => None,
        }
    }

    // linker and linker flavor specified via command line have precedence over what the target
    // specification specifies
    if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), sess.opts.cg.linker_flavor) {
        return ret;
    }

    if let Some(ret) = infer_from(
        sess,
        sess.target.linker.clone().map(PathBuf::from),
        Some(sess.target.linker_flavor),
    ) {
        return ret;
    }

    bug!("Not enough information provided to determine how to invoke the linker");
}
<|endoftext|>


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

use structure::*;

use approx::ApproxEq;
use matrix::{Matrix2, Matrix3, Matrix4};
use num::{BaseFloat, BaseNum};
use point::{Point2, Point3};
use rotation::*;
use vector::{Vector2, Vector3};

/// A trait representing an [affine
/// transformation](https://en.wikipedia.org/wiki/Affine_transformation) that
/// can be applied to points or vectors. An affine transformation is one which
pub trait Transform<P: EuclideanSpace>: Sized {
    /// Create an identity transformation. That is, a transformation which
    /// does nothing.
    fn one() -> Self;

    /// Create a transformation that rotates a vector to look at `center` from
    /// `eye`, using `up` for orientation.
    fn look_at(eye: P, center: P, up: P::Diff) -> Self;

    /// Transform a vector using this transform.
    fn transform_vector(&self, vec: P::Diff) -> P::Diff;

    /// Transform a point using this transform.
    fn transform_point(&self, point: P) -> P;

    /// Combine this transform with another, yielding a new transformation
    /// which has the effects of both.
    fn concat(&self, other: &Self) -> Self;

    /// Create a transform that "un-does" this one.
    fn inverse_transform(&self) -> Option<Self>;

    /// Combine this transform with another, in-place.
    #[inline]
    fn concat_self(&mut self, other: &Self) {
        *self = Self::concat(self, other);
    }
}

/// A generic transformation consisting of a rotation,
/// displacement vector and scale amount.
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
pub struct Decomposed<V: VectorSpace, R> {
    pub scale: V::Scalar,
    pub rot: R,
    pub disp: V,
}

impl<P: EuclideanSpace, R: Rotation<P>> Transform<P> for Decomposed<P::Diff, R> where
    // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
    <P as EuclideanSpace>::Scalar: BaseFloat,
    // FIXME: Investigate why this is needed!
    <P as EuclideanSpace>::Diff: VectorSpace,
{
    #[inline]
    fn one() -> Decomposed<P::Diff, R> {
        Decomposed {
            scale: P::Scalar::one(),
            rot: R::one(),
            disp: P::Diff::zero(),
        }
    }

    #[inline]
    fn look_at(eye: P, center: P, up: P::Diff) -> Decomposed<P::Diff, R> {
        let rot = R::look_at(center - eye, up);
        let disp = rot.rotate_vector(P::origin() - eye);
        Decomposed {
            scale: P::Scalar::one(),
            rot: rot,
            disp: disp,
        }
    }

    #[inline]
    fn transform_vector(&self, vec: P::Diff) -> P::Diff {
        self.rot.rotate_vector(vec * self.scale)
    }

    #[inline]
    fn transform_point(&self, point: P) -> P {
        self.rot.rotate_point(point * self.scale) + self.disp
    }

    fn concat(&self, other: &Decomposed<P::Diff, R>) -> Decomposed<P::Diff, R> {
        Decomposed {
            scale: self.scale * other.scale,
            rot: self.rot * other.rot,
            disp: self.disp + other.disp,
        }
    }

    fn inverse_transform(&self) -> Option<Decomposed<P::Diff, R>> {
        if self.scale.approx_eq(&P::Scalar::zero()) {
            None
        } else {
            let s = P::Scalar::one() / self.scale;
            let r = self.rot.invert();
            let d = r.rotate_vector(self.disp.clone()) * -s;
            Some(Decomposed {
                scale: s,
                rot: r,
                disp: d,
            })
        }
    }
}

pub trait Transform2<S: BaseNum>: Transform<Point2<S>> + Into<Matrix3<S>> {}
pub trait Transform3<S: BaseNum>: Transform<Point3<S>> + Into<Matrix4<S>> {}

impl<S: BaseFloat, R: Rotation2<S>> From<Decomposed<Vector2<S>, R>> for Matrix3<S> {
    fn from(dec: Decomposed<Vector2<S>, R>) -> Matrix3<S> {
        let m: Matrix2<_> = dec.rot.into();
        let mut m: Matrix3<_> = (&m * dec.scale).into();
        m.z = dec.disp.extend(S::one());
        m
    }
}

impl<S: BaseFloat, R: Rotation3<S>> From<Decomposed<Vector3<S>, R>> for Matrix4<S> {
    fn from(dec: Decomposed<Vector3<S>, R>) -> Matrix4<S> {
        let m: Matrix3<_> = dec.rot.into();
        let mut m: Matrix4<_> = (&m * dec.scale).into();
        m.w = dec.disp.extend(S::one());
        m
    }
}

impl<S: BaseFloat, R: Rotation2<S>> Transform2<S> for Decomposed<Vector2<S>, R> {}

impl<S: BaseFloat, R: Rotation3<S>> Transform3<S> for Decomposed<Vector3<S>, R> {}

impl<S: VectorSpace, R, E: BaseFloat> ApproxEq for Decomposed<S, R>
    where S: ApproxEq<Epsilon = E>, S::Scalar: ApproxEq<Epsilon = E>, R: ApproxEq<Epsilon = E>
{
    type Epsilon = E;

    fn approx_eq_eps(&self, other: &Self, epsilon: &Self::Epsilon) -> bool {
        self.scale.approx_eq_eps(&other.scale, epsilon) &&
        self.rot.approx_eq_eps(&other.rot, epsilon) &&
        self.disp.approx_eq_eps(&other.disp, epsilon)
    }
}

#[cfg(feature = "eders")]
#[doc(hidden)]
mod eders_ser {
    use structure::VectorSpace;
    use super::Decomposed;
    use serde::{self, Serialize};

    impl<V: VectorSpace, R> Serialize for Decomposed<V, R>
        where V: Serialize, V::Scalar: Serialize, R: Serialize
    {
        fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
            where S: serde::Serializer
        {
            serializer.serialize_struct("Decomposed", DecomposedVisitor {
                value: self,
                state: 0,
            })
        }
    }

    struct DecomposedVisitor<'a, V: 'a + VectorSpace, R: 'a> {
        value: &'a Decomposed<V, R>,
        state: u8,
    }

    impl<'a, V: 'a + VectorSpace, R> serde::ser::MapVisitor for DecomposedVisitor<'a, V, R>
        where V: Serialize, V::Scalar: Serialize, R: Serialize
    {
        fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
            where S: serde::Serializer
        {
            match self.state {
                0 => {
                    self.state += 1;
                    Ok(Some(try!(serializer.serialize_struct_elt("scale", &self.value.scale))))
                },
                1 => {
                    self.state += 1;
                    Ok(Some(try!(serializer.serialize_struct_elt("rot", &self.value.rot))))
                },
                2 => {
                    self.state += 1;
                    Ok(Some(try!(serializer.serialize_struct_elt("disp", &self.value.disp))))
                },
                _ => {
                    Ok(None)
                },
            }
        }
    }
}

#[cfg(feature = "eders")]
#[doc(hidden)]
mod eders_de {
    use structure::VectorSpace;
    use super::Decomposed;
    use serde::{self, Deserialize};
    use std::marker::PhantomData;

    enum DecomposedField {
        Scale,
        Rot,
        Disp,
    }

    impl Deserialize for DecomposedField {
        fn deserialize<D>(deserializer: &mut D) -> Result<DecomposedField, D::Error>
            where D: serde::Deserializer
        {
            struct DecomposedFieldVisitor;

            impl serde::de::Visitor for DecomposedFieldVisitor {
                type Value = DecomposedField;

                fn visit_str<E>(&mut self, value: &str) -> Result<DecomposedField, E>
                    where E: serde::de::Error
                {
                    match value {
                        "scale" => Ok(DecomposedField::Scale),
                        "rot" => Ok(DecomposedField::Rot),
                        "disp" => Ok(DecomposedField::Disp),
                        _ => Err(serde::de::Error::custom("expected scale, rot or disp")),
                    }
                }
            }

            deserializer.deserialize(DecomposedFieldVisitor)
        }
    }

    impl<S: VectorSpace, R> Deserialize for Decomposed<S, R>
        where S: Deserialize, S::Scalar: Deserialize, R: Deserialize
    {
        fn deserialize<D>(deserializer: &mut D) -> Result<Decomposed<S, R>, D::Error>
            where D: serde::de::Deserializer
        {
            const FIELDS: &'static [&'static str] = &["scale", "rot", "disp"];
            deserializer.deserialize_struct("Decomposed", FIELDS, DecomposedVisitor(PhantomData))
        }
    }

    struct DecomposedVisitor<S: VectorSpace, R>(PhantomData<(S, R)>);

    impl<S: VectorSpace, R> serde::de::Visitor for DecomposedVisitor<S, R>
        where S: Deserialize, S::Scalar: Deserialize, R: Deserialize
    {
        type Value = Decomposed<S, R>;

        fn visit_map<V>(&mut self, mut visitor: V) -> Result<Decomposed<S, R>, V::Error>
            where V: serde::de::MapVisitor
        {
            let mut scale = None;
            let mut rot = None;
            let mut disp = None;

            loop {
                match try!(visitor.visit_key()) {
                    Some(DecomposedField::Scale) => { scale = Some(try!(visitor.visit_value())); },
                    Some(DecomposedField::Rot) => { rot = Some(try!(visitor.visit_value())); },
                    Some(DecomposedField::Disp) => { disp = Some(try!(visitor.visit_value())); },
                    _ => { break; },
                }
            }

            let scale = match scale {
                Some(scale) => scale,
                None => try!(visitor.missing_field("scale")),
            };

            let rot = match rot {
                Some(rot) => rot,
                None => try!(visitor.missing_field("rot")),
            };

            let disp = match disp {
                Some(disp) => disp,
                None => try!(visitor.missing_field("disp")),
            };

            try!(visitor.end());

            Ok(Decomposed { scale: scale, rot: rot, disp: disp })
        }
    }
}
<commit_msg>Fixed Decomposed::concat<commit_after>// Copyright 2014 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use structure::*;

use approx::ApproxEq;
use matrix::{Matrix2, Matrix3, Matrix4};
use num::{BaseFloat, BaseNum};
use point::{Point2, Point3};
use rotation::*;
use vector::{Vector2, Vector3};

/// A trait representing an [affine
/// transformation](https://en.wikipedia.org/wiki/Affine_transformation) that
/// can be applied to points or vectors. An affine transformation is one which
pub trait Transform<P: EuclideanSpace>: Sized {
    /// Create an identity transformation. That is, a transformation which
    /// does nothing.
    fn one() -> Self;

    /// Create a transformation that rotates a vector to look at `center` from
    /// `eye`, using `up` for orientation.
    fn look_at(eye: P, center: P, up: P::Diff) -> Self;

    /// Transform a vector using this transform.
    fn transform_vector(&self, vec: P::Diff) -> P::Diff;

    /// Transform a point using this transform.
    fn transform_point(&self, point: P) -> P;

    /// Combine this transform with another, yielding a new transformation
    /// which has the effects of both.
    fn concat(&self, other: &Self) -> Self;

    /// Create a transform that "un-does" this one.
    fn inverse_transform(&self) -> Option<Self>;

    /// Combine this transform with another, in-place.
    #[inline]
    fn concat_self(&mut self, other: &Self) {
        *self = Self::concat(self, other);
    }
}

/// A generic transformation consisting of a rotation,
/// displacement vector and scale amount.
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
pub struct Decomposed<V: VectorSpace, R> {
    pub scale: V::Scalar,
    pub rot: R,
    pub disp: V,
}

impl<P: EuclideanSpace, R: Rotation<P>> Transform<P> for Decomposed<P::Diff, R> where
    // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
    <P as EuclideanSpace>::Scalar: BaseFloat,
    // FIXME: Investigate why this is needed!
    <P as EuclideanSpace>::Diff: VectorSpace,
{
    #[inline]
    fn one() -> Decomposed<P::Diff, R> {
        Decomposed {
            scale: P::Scalar::one(),
            rot: R::one(),
            disp: P::Diff::zero(),
        }
    }

    #[inline]
    fn look_at(eye: P, center: P, up: P::Diff) -> Decomposed<P::Diff, R> {
        let rot = R::look_at(center - eye, up);
        let disp = rot.rotate_vector(P::origin() - eye);
        Decomposed {
            scale: P::Scalar::one(),
            rot: rot,
            disp: disp,
        }
    }

    #[inline]
    fn transform_vector(&self, vec: P::Diff) -> P::Diff {
        self.rot.rotate_vector(vec * self.scale)
    }

    #[inline]
    fn transform_point(&self, point: P) -> P {
        self.rot.rotate_point(point * self.scale) + self.disp
    }

    fn concat(&self, other: &Decomposed<P::Diff, R>) -> Decomposed<P::Diff, R> {
        Decomposed {
            scale: self.scale * other.scale,
            rot: self.rot * other.rot,
            disp: self.rot.rotate_vector(other.disp * self.scale) + self.disp,
        }
    }

    fn inverse_transform(&self) -> Option<Decomposed<P::Diff, R>> {
        if self.scale.approx_eq(&P::Scalar::zero()) {
            None
        } else {
            let s = P::Scalar::one() / self.scale;
            let r = self.rot.invert();
            let d = r.rotate_vector(self.disp.clone()) * -s;
            Some(Decomposed {
                scale: s,
                rot: r,
                disp: d,
            })
        }
    }
}

pub trait Transform2<S: BaseNum>: Transform<Point2<S>> + Into<Matrix3<S>> {}
pub trait Transform3<S: BaseNum>: Transform<Point3<S>> + Into<Matrix4<S>> {}

impl<S: BaseFloat, R: Rotation2<S>> From<Decomposed<Vector2<S>, R>> for Matrix3<S> {
    fn from(dec: Decomposed<Vector2<S>, R>) -> Matrix3<S> {
        let m: Matrix2<_> = dec.rot.into();
        let mut m: Matrix3<_> = (&m * dec.scale).into();
        m.z = dec.disp.extend(S::one());
        m
    }
}

impl<S: BaseFloat, R: Rotation3<S>> From<Decomposed<Vector3<S>, R>> for Matrix4<S> {
    fn from(dec: Decomposed<Vector3<S>, R>) -> Matrix4<S> {
        let m: Matrix3<_> = dec.rot.into();
        let mut m: Matrix4<_> = (&m * dec.scale).into();
        m.w = dec.disp.extend(S::one());
        m
    }
}

impl<S: BaseFloat, R: Rotation2<S>> Transform2<S> for Decomposed<Vector2<S>, R> {}

impl<S: BaseFloat, R: Rotation3<S>> Transform3<S> for Decomposed<Vector3<S>, R> {}

impl<S: VectorSpace, R, E: BaseFloat> ApproxEq for Decomposed<S, R>
    where S: ApproxEq<Epsilon = E>, S::Scalar: ApproxEq<Epsilon = E>, R: ApproxEq<Epsilon = E>
{
    type Epsilon = E;

    fn approx_eq_eps(&self, other: &Self, epsilon: &Self::Epsilon) -> bool {
        self.scale.approx_eq_eps(&other.scale, epsilon) &&
        self.rot.approx_eq_eps(&other.rot, epsilon) &&
        self.disp.approx_eq_eps(&other.disp, epsilon)
    }
}

#[cfg(feature = "eders")]
#[doc(hidden)]
mod eders_ser {
    use structure::VectorSpace;
    use super::Decomposed;
    use serde::{self, Serialize};

    impl<V: VectorSpace, R> Serialize for Decomposed<V, R>
        where V: Serialize, V::Scalar: Serialize, R: Serialize
    {
        fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
            where S: serde::Serializer
        {
            serializer.serialize_struct("Decomposed", DecomposedVisitor {
                value: self,
                state: 0,
            })
        }
    }

    struct DecomposedVisitor<'a, V: 'a + VectorSpace, R: 'a> {
        value: &'a Decomposed<V, R>,
        state: u8,
    }

    impl<'a, V: 'a + VectorSpace, R> serde::ser::MapVisitor for DecomposedVisitor<'a, V, R>
        where V: Serialize, V::Scalar: Serialize, R: Serialize
    {
        fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
            where S: serde::Serializer
        {
            match self.state {
                0 => {
                    self.state += 1;
                    Ok(Some(try!(serializer.serialize_struct_elt("scale", &self.value.scale))))
                },
                1 => {
                    self.state += 1;
                    Ok(Some(try!(serializer.serialize_struct_elt("rot", &self.value.rot))))
                },
                2 => {
                    self.state += 1;
                    Ok(Some(try!(serializer.serialize_struct_elt("disp", &self.value.disp))))
                },
                _ => {
                    Ok(None)
                },
            }
        }
    }
}

#[cfg(feature = "eders")]
#[doc(hidden)]
mod eders_de {
    use structure::VectorSpace;
    use super::Decomposed;
    use serde::{self, Deserialize};
    use std::marker::PhantomData;

    enum DecomposedField {
        Scale,
        Rot,
        Disp,
    }

    impl Deserialize for DecomposedField {
        fn deserialize<D>(deserializer: &mut D) -> Result<DecomposedField, D::Error>
            where D: serde::Deserializer
        {
            struct DecomposedFieldVisitor;

            impl serde::de::Visitor for DecomposedFieldVisitor {
                type Value = DecomposedField;

                fn visit_str<E>(&mut self, value: &str) -> Result<DecomposedField, E>
                    where E: serde::de::Error
                {
                    match value {
                        "scale" => Ok(DecomposedField::Scale),
                        "rot" => Ok(DecomposedField::Rot),
                        "disp" => Ok(DecomposedField::Disp),
                        _ => Err(serde::de::Error::custom("expected scale, rot or disp")),
                    }
                }
            }

            deserializer.deserialize(DecomposedFieldVisitor)
        }
    }

    impl<S: VectorSpace, R> Deserialize for Decomposed<S, R>
        where S: Deserialize, S::Scalar: Deserialize, R: Deserialize
    {
        fn deserialize<D>(deserializer: &mut D) -> Result<Decomposed<S, R>, D::Error>
            where D: serde::de::Deserializer
        {
            const FIELDS: &'static [&'static str] = &["scale", "rot", "disp"];
            deserializer.deserialize_struct("Decomposed", FIELDS, DecomposedVisitor(PhantomData))
        }
    }

    struct DecomposedVisitor<S: VectorSpace, R>(PhantomData<(S, R)>);

    impl<S: VectorSpace, R> serde::de::Visitor for DecomposedVisitor<S, R>
        where S: Deserialize, S::Scalar: Deserialize, R: Deserialize
    {
        type Value = Decomposed<S, R>;

        fn visit_map<V>(&mut self, mut visitor: V) -> Result<Decomposed<S, R>, V::Error>
            where V: serde::de::MapVisitor
        {
            let mut scale = None;
            let mut rot = None;
            let mut disp = None;

            loop {
                match try!(visitor.visit_key()) {
                    Some(DecomposedField::Scale) => { scale = Some(try!(visitor.visit_value())); },
                    Some(DecomposedField::Rot) => { rot = Some(try!(visitor.visit_value())); },
                    Some(DecomposedField::Disp) => { disp = Some(try!(visitor.visit_value())); },
                    _ => { break; },
                }
            }

            let scale = match scale {
                Some(scale) => scale,
                None => try!(visitor.missing_field("scale")),
            };

            let rot = match rot {
                Some(rot) => rot,
                None => try!(visitor.missing_field("rot")),
            };

            let disp = match disp {
                Some(disp) => disp,
                None => try!(visitor.missing_field("disp")),
            };

            try!(visitor.end());

            Ok(Decomposed { scale: scale, rot: rot, disp: disp })
        }
    }
}
<|endoftext|>