<commit_before>use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use core::fmt;
use core::default::Default;
use util::cpu_relax;

/// A reader-writer lock
///
/// This type of lock allows a number of readers or at most one writer at any
/// point in time. The write portion of this lock typically allows modification
/// of the underlying data (exclusive access) and the read portion of this lock
/// typically allows for read-only access (shared access).
///
/// The type parameter `T` represents the data that this lock protects. It is
/// required that `T` satisfies `Send` to be shared across tasks and `Sync` to
/// allow concurrent access through readers. The RAII guards returned from the
/// locking methods implement `Deref` (and `DerefMut` for the `write` methods)
/// to allow access to the contained of the lock.
///
/// Based on
/// https://jfdube.wordpress.com/2014/01/03/implementing-a-recursive-read-write-spinlock/
///
pub struct RwLock<T>
{
    lock: AtomicUsize,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be read
///
/// When the guard falls out of scope it will decrement the read count,
/// potentially releasing the lock.
pub struct RwLockReadGuard<'a, T:'a>
{
    lock: &'a AtomicUsize,
    data: &'a T,
}

/// A guard to which the protected data can be written
///
/// When the guard falls out of scope it will release the lock.
pub struct RwLockWriteGuard<'a, T:'a>
{
    lock: &'a AtomicUsize,
    data: &'a mut T,
}

unsafe impl<T> Sync for RwLock<T> {}
unsafe impl<T:'static+Send> Send for RwLock<T> {}

const USIZE_MSB: usize = ::core::isize::MIN as usize;

impl<T> RwLock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    ///
    /// May be used statically:
    ///
    /// ```
    /// #![feature(const_fn)]
    /// use spin;
    ///
    /// static RW_LOCK: spin::RwLock<()> = spin::RwLock::new(());
    ///
    /// fn demo() {
    ///     let lock = RW_LOCK.read();
    ///     // do something with lock
    ///     drop(lock);
    /// }
    /// ```
    #[inline]
    pub const fn new(user_data: T) -> RwLock<T>
    {
        RwLock
        {
            lock: ATOMIC_USIZE_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    /// Locks this rwlock with shared read access, blocking the current thread
    /// until it can be acquired.
    ///
    /// The calling thread will be blocked until there are no more writers which
    /// hold the lock. There may be other readers currently inside the lock when
    /// this method returns. This method does not provide any guarantees with
    /// respect to the ordering of whether contentious readers or writers will
    /// acquire the lock first.
    ///
    /// Returns an RAII guard which will release this thread's shared access
    /// once it is dropped.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0);
    /// {
    ///     let mut data = mylock.read();
    ///     // The lock is now locked and the data can be read
    ///     println!("{}", *data);
    ///     // The lock is dropped
    /// }
    /// ```
    #[inline]
    pub fn read<'a>(&'a self) -> RwLockReadGuard<'a, T>
    {
        // (funny do-while loop)
        while {
            // Old value, with write bit unset
            let mut old;

            // Wait for for writer to go away before doing expensive atomic ops
            // (funny do-while loop)
            while {
                old = self.lock.load(Ordering::Relaxed);
                old & USIZE_MSB != 0
            } {
                cpu_relax();
            }

            // unset write bit
            old &= !USIZE_MSB;

            let new = old + 1;
            debug_assert!(new != (!USIZE_MSB) & (!0));

            self.lock.compare_and_swap(old, new, Ordering::SeqCst) != old
        } {
            cpu_relax();
        }
        RwLockReadGuard {
            lock: &self.lock,
            data: unsafe { & *self.data.get() },
        }
    }

    /// Attempt to acquire this lock with shared read access.
    ///
    /// This function will never block and will return immediately if `read`
    /// would otherwise succeed. Returns `Some` of an RAII guard which will
    /// release the shared access of this thread when dropped, or `None` if the
    /// access could not be granted. This method does not provide any
    /// guarantees with respect to the ordering of whether contentious readers
    /// or writers will acquire the lock first.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0);
    /// {
    ///     match mylock.try_read() {
    ///         Some(data) => {
    ///             // The lock is now locked and the data can be read
    ///             println!("{}", *data);
    ///             // The lock is dropped
    ///         },
    ///         None => (), // no cigar
    ///     };
    /// }
    /// ```
    #[inline]
    pub fn try_read(&self) -> Option<RwLockReadGuard<T>>
    {
        // Old value, with write bit unset
        let old = (!USIZE_MSB) & self.lock.load(Ordering::Relaxed);

        let new = old + 1;
        debug_assert!(new != (!USIZE_MSB) & (!0));
        if self.lock.compare_and_swap(old,
                                      new,
                                      Ordering::SeqCst) == old
        {
            Some(RwLockReadGuard {
                lock: &self.lock,
                data: unsafe { & *self.data.get() },
            })
        } else {
            None
        }
    }

    /// Lock this rwlock with exclusive write access, blocking the current
    /// thread until it can be acquired.
    ///
    /// This function will not return while other writers or other readers
    /// currently have access to the lock.
    ///
    /// Returns an RAII guard which will drop the write access of this rwlock
    /// when dropped.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0);
    /// {
    ///     let mut data = mylock.write();
    ///     // The lock is now locked and the data can be written
    ///     *data += 1;
    ///     // The lock is dropped
    /// }
    /// ```
    #[inline]
    pub fn write<'a>(&'a self) -> RwLockWriteGuard<'a, T>
    {
        loop
        {
            // Old value, with write bit unset.
            let old = (!USIZE_MSB) & self.lock.load(Ordering::Relaxed);
            // Old value, with write bit set.
            let new = USIZE_MSB | old;
            if self.lock.compare_and_swap(old,
                                          new,
                                          Ordering::SeqCst) == old
            {
                // Wait for readers to go away, then lock is ours.
                while self.lock.load(Ordering::Relaxed) != USIZE_MSB {
                    cpu_relax();
                }
                break
            }
        }
        RwLockWriteGuard {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }

    /// Attempt to lock this rwlock with exclusive write access.
    ///
    /// This function does not ever block, and it will return `None` if a call
    /// to `write` would otherwise block. If successful, an RAII guard is
    /// returned.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0);
    /// {
    ///     match mylock.try_write() {
    ///         Some(mut data) => {
    ///             // The lock is now locked and the data can be written
    ///             *data += 1;
    ///             // The lock is implicitly dropped
    ///         },
    ///         None => (), // no cigar
    ///     };
    /// }
    /// ```
    #[inline]
    pub fn try_write(&self) -> Option<RwLockWriteGuard<T>>
    {
        if self.lock.compare_and_swap(0,
                                      USIZE_MSB,
                                      Ordering::SeqCst) == 0
        {
            Some(RwLockWriteGuard {
                lock: &self.lock,
                data: unsafe { &mut *self.data.get() },
            })
        } else {
            None
        }
    }
}

impl<T: fmt::Debug> fmt::Debug for RwLock<T>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match self.try_read()
        {
            Some(guard) => write!(f, "RwLock {{ data: {:?} }}", &*guard),
            None => write!(f, "RwLock {{ <locked> }}"),
        }
    }
}

impl<T: Default> Default for RwLock<T> {
    fn default() -> RwLock<T> {
        RwLock::new(Default::default())
    }
}

impl<'rwlock, T> Deref for RwLockReadGuard<'rwlock, T> {
    type Target = T;

    fn deref(&self) -> &T { self.data }
}

impl<'rwlock, T> Deref for RwLockWriteGuard<'rwlock, T> {
    type Target = T;

    fn deref(&self) -> &T { self.data }
}

impl<'rwlock, T> DerefMut for RwLockWriteGuard<'rwlock, T> {
    fn deref_mut(&mut self) -> &mut T { self.data }
}

impl<'rwlock, T> Drop for RwLockReadGuard<'rwlock, T> {
    fn drop(&mut self) {
        debug_assert!(self.lock.load(Ordering::Relaxed) & (!USIZE_MSB) > 0);
        self.lock.fetch_sub(1, Ordering::SeqCst);
    }
}

impl<'rwlock, T> Drop for RwLockWriteGuard<'rwlock, T> {
    fn drop(&mut self) {
        debug_assert_eq!(self.lock.load(Ordering::Relaxed), USIZE_MSB);
        self.lock.store(0, Ordering::Relaxed);
    }
}
<commit_msg>Add RwLock example from std<commit_after>use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use core::fmt;
use core::default::Default;
use util::cpu_relax;

/// A reader-writer lock
///
/// This type of lock allows a number of readers or at most one writer at any
/// point in time. The write portion of this lock typically allows modification
/// of the underlying data (exclusive access) and the read portion of this lock
/// typically allows for read-only access (shared access).
///
/// The type parameter `T` represents the data that this lock protects. It is
/// required that `T` satisfies `Send` to be shared across tasks and `Sync` to
/// allow concurrent access through readers. The RAII guards returned from the
/// locking methods implement `Deref` (and `DerefMut` for the `write` methods)
/// to allow access to the contained of the lock.
///
/// Based on
/// https://jfdube.wordpress.com/2014/01/03/implementing-a-recursive-read-write-spinlock/
///
/// # Examples
///
/// ```
/// use spin;
///
/// let lock = spin::RwLock::new(5);
///
/// // many reader locks can be held at once
/// {
///     let r1 = lock.read();
///     let r2 = lock.read();
///     assert_eq!(*r1, 5);
///     assert_eq!(*r2, 5);
/// } // read locks are dropped at this point
///
/// // only one write lock may be held, however
/// {
///     let mut w = lock.write();
///     *w += 1;
///     assert_eq!(*w, 6);
/// } // write lock is dropped here
/// ```
pub struct RwLock<T>
{
    lock: AtomicUsize,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be read
///
/// When the guard falls out of scope it will decrement the read count,
/// potentially releasing the lock.
pub struct RwLockReadGuard<'a, T:'a>
{
    lock: &'a AtomicUsize,
    data: &'a T,
}

/// A guard to which the protected data can be written
///
/// When the guard falls out of scope it will release the lock.
pub struct RwLockWriteGuard<'a, T:'a>
{
    lock: &'a AtomicUsize,
    data: &'a mut T,
}

unsafe impl<T> Sync for RwLock<T> {}
unsafe impl<T:'static+Send> Send for RwLock<T> {}

const USIZE_MSB: usize = ::core::isize::MIN as usize;

impl<T> RwLock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    ///
    /// May be used statically:
    ///
    /// ```
    /// #![feature(const_fn)]
    /// use spin;
    ///
    /// static RW_LOCK: spin::RwLock<()> = spin::RwLock::new(());
    ///
    /// fn demo() {
    ///     let lock = RW_LOCK.read();
    ///     // do something with lock
    ///     drop(lock);
    /// }
    /// ```
    #[inline]
    pub const fn new(user_data: T) -> RwLock<T>
    {
        RwLock
        {
            lock: ATOMIC_USIZE_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    /// Locks this rwlock with shared read access, blocking the current thread
    /// until it can be acquired.
    ///
    /// The calling thread will be blocked until there are no more writers which
    /// hold the lock. There may be other readers currently inside the lock when
    /// this method returns. This method does not provide any guarantees with
    /// respect to the ordering of whether contentious readers or writers will
    /// acquire the lock first.
    ///
    /// Returns an RAII guard which will release this thread's shared access
    /// once it is dropped.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0);
    /// {
    ///     let mut data = mylock.read();
    ///     // The lock is now locked and the data can be read
    ///     println!("{}", *data);
    ///     // The lock is dropped
    /// }
    /// ```
    #[inline]
    pub fn read<'a>(&'a self) -> RwLockReadGuard<'a, T>
    {
        // (funny do-while loop)
        while {
            // Old value, with write bit unset
            let mut old;

            // Wait for for writer to go away before doing expensive atomic ops
            // (funny do-while loop)
            while {
                old = self.lock.load(Ordering::Relaxed);
                old & USIZE_MSB != 0
            } {
                cpu_relax();
            }

            // unset write bit
            old &= !USIZE_MSB;

            let new = old + 1;
            debug_assert!(new != (!USIZE_MSB) & (!0));

            self.lock.compare_and_swap(old, new, Ordering::SeqCst) != old
        } {
            cpu_relax();
        }
        RwLockReadGuard {
            lock: &self.lock,
            data: unsafe { & *self.data.get() },
        }
    }

    /// Attempt to acquire this lock with shared read access.
    ///
    /// This function will never block and will return immediately if `read`
    /// would otherwise succeed. Returns `Some` of an RAII guard which will
    /// release the shared access of this thread when dropped, or `None` if the
    /// access could not be granted. This method does not provide any
    /// guarantees with respect to the ordering of whether contentious readers
    /// or writers will acquire the lock first.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0);
    /// {
    ///     match mylock.try_read() {
    ///         Some(data) => {
    ///             // The lock is now locked and the data can be read
    ///             println!("{}", *data);
    ///             // The lock is dropped
    ///         },
    ///         None => (), // no cigar
    ///     };
    /// }
    /// ```
    #[inline]
    pub fn try_read(&self) -> Option<RwLockReadGuard<T>>
    {
        // Old value, with write bit unset
        let old = (!USIZE_MSB) & self.lock.load(Ordering::Relaxed);

        let new = old + 1;
        debug_assert!(new != (!USIZE_MSB) & (!0));
        if self.lock.compare_and_swap(old,
                                      new,
                                      Ordering::SeqCst) == old
        {
            Some(RwLockReadGuard {
                lock: &self.lock,
                data: unsafe { & *self.data.get() },
            })
        } else {
            None
        }
    }

    /// Lock this rwlock with exclusive write access, blocking the current
    /// thread until it can be acquired.
    ///
    /// This function will not return while other writers or other readers
    /// currently have access to the lock.
    ///
    /// Returns an RAII guard which will drop the write access of this rwlock
    /// when dropped.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0);
    /// {
    ///     let mut data = mylock.write();
    ///     // The lock is now locked and the data can be written
    ///     *data += 1;
    ///     // The lock is dropped
    /// }
    /// ```
    #[inline]
    pub fn write<'a>(&'a self) -> RwLockWriteGuard<'a, T>
    {
        loop
        {
            // Old value, with write bit unset.
            let old = (!USIZE_MSB) & self.lock.load(Ordering::Relaxed);
            // Old value, with write bit set.
            let new = USIZE_MSB | old;
            if self.lock.compare_and_swap(old,
                                          new,
                                          Ordering::SeqCst) == old
            {
                // Wait for readers to go away, then lock is ours.
                while self.lock.load(Ordering::Relaxed) != USIZE_MSB {
                    cpu_relax();
                }
                break
            }
        }
        RwLockWriteGuard {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }

    /// Attempt to lock this rwlock with exclusive write access.
    ///
    /// This function does not ever block, and it will return `None` if a call
    /// to `write` would otherwise block. If successful, an RAII guard is
    /// returned.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0);
    /// {
    ///     match mylock.try_write() {
    ///         Some(mut data) => {
    ///             // The lock is now locked and the data can be written
    ///             *data += 1;
    ///             // The lock is implicitly dropped
    ///         },
    ///         None => (), // no cigar
    ///     };
    /// }
    /// ```
    #[inline]
    pub fn try_write(&self) -> Option<RwLockWriteGuard<T>>
    {
        if self.lock.compare_and_swap(0,
                                      USIZE_MSB,
                                      Ordering::SeqCst) == 0
        {
            Some(RwLockWriteGuard {
                lock: &self.lock,
                data: unsafe { &mut *self.data.get() },
            })
        } else {
            None
        }
    }
}

impl<T: fmt::Debug> fmt::Debug for RwLock<T>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match self.try_read()
        {
            Some(guard) => write!(f, "RwLock {{ data: {:?} }}", &*guard),
            None => write!(f, "RwLock {{ <locked> }}"),
        }
    }
}

impl<T: Default> Default for RwLock<T> {
    fn default() -> RwLock<T> {
        RwLock::new(Default::default())
    }
}

impl<'rwlock, T> Deref for RwLockReadGuard<'rwlock, T> {
    type Target = T;

    fn deref(&self) -> &T { self.data }
}

impl<'rwlock, T> Deref for RwLockWriteGuard<'rwlock, T> {
    type Target = T;

    fn deref(&self) -> &T { self.data }
}

impl<'rwlock, T> DerefMut for RwLockWriteGuard<'rwlock, T> {
    fn deref_mut(&mut self) -> &mut T { self.data }
}

impl<'rwlock, T> Drop for RwLockReadGuard<'rwlock, T> {
    fn drop(&mut self) {
        debug_assert!(self.lock.load(Ordering::Relaxed) & (!USIZE_MSB) > 0);
        self.lock.fetch_sub(1, Ordering::SeqCst);
    }
}

impl<'rwlock, T> Drop for RwLockWriteGuard<'rwlock, T> {
    fn drop(&mut self) {
        debug_assert_eq!(self.lock.load(Ordering::Relaxed), USIZE_MSB);
        self.lock.store(0, Ordering::Relaxed);
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use id::IdRef;
use owned::{DropInPlace, Owned};

use llvm_sys::prelude::LLVMPassManagerRef;
use llvm_sys::core::{LLVMCreateFunctionPassManagerForModule, LLVMDisposePassManager};
use llvm_sys::core::{LLVMInitializeFunctionPassManager, LLVMFinalizeFunctionPassManager};
use llvm_sys::core::LLVMRunFunctionPassManager;
use llvm_sys::transforms::scalar::{
    LLVMAddBasicAliasAnalysisPass,
    LLVMAddGVNPass,
    LLVMAddInstructionCombiningPass,
    LLVMAddDemoteMemoryToRegisterPass,
    LLVMAddReassociatePass,
    LLVMAddCFGSimplificationPass
};

use llvm::{Function, Module, ModuleBuilder};

pub struct FunctionPassManager<'mid> {
    _module_id: IdRef<'mid>
}

impl<'mid> DropInPlace for FunctionPassManager<'mid> {
    unsafe fn drop_in_place(&mut self) {
        LLVMDisposePassManager(self.as_raw());
    }
}

impl<'mid> FunctionPassManager<'mid> {
    pub fn new<'cid, 'context>(module: &Module<'cid, 'context, 'mid>) -> Owned<FunctionPassManager<'mid>> {
        unsafe {
            Owned::from_raw(LLVMCreateFunctionPassManagerForModule(module.as_raw()) as *mut FunctionPassManager)
        }
    }

    pub fn add_basic_alias_analysis(&mut self) {
        unsafe {
            LLVMAddBasicAliasAnalysisPass(self.as_raw());
        }
    }

    pub fn add_gvn(&mut self) {
        unsafe {
            LLVMAddGVNPass(self.as_raw());
        }
    }

    pub fn add_instruction_combine(&mut self) {
        unsafe {
            LLVMAddInstructionCombiningPass(self.as_raw());
        }
    }

    pub fn add_memory_to_register(&mut self) {
        unsafe {
            LLVMAddDemoteMemoryToRegisterPass(self.as_raw());
        }
    }

    pub fn add_reassociate(&mut self) {
        unsafe {
            LLVMAddReassociatePass(self.as_raw());
        }
    }

    pub fn add_simplify_cfg(&mut self) {
        unsafe {
            LLVMAddCFGSimplificationPass(self.as_raw());
        }
    }

    pub fn initialize<'fpm, 'cid, 'module>(&'fpm mut self, _module: &ModuleBuilder<'cid, 'mid, 'module>) -> Owned<InitializedFunctionPassManager<'mid, 'module, 'fpm>> {
        unsafe {
            LLVMInitializeFunctionPassManager(self.as_raw());
            Owned::from_raw(self.as_raw() as *mut InitializedFunctionPassManager)
        }
    }

    pub fn as_raw(&self) -> LLVMPassManagerRef {
        self as *const FunctionPassManager as *mut FunctionPassManager as LLVMPassManagerRef
    }
}

pub struct InitializedFunctionPassManager<'mid: 'module + 'fpm, 'module, 'fpm> {
    _marker: PhantomData<(&'module mut Module<'static, 'static, 'mid>, &'fpm mut FunctionPassManager<'mid>)>
}

impl<'mid, 'module, 'fpm> DropInPlace for InitializedFunctionPassManager<'mid, 'module, 'fpm> {
    unsafe fn drop_in_place(&mut self) {
        LLVMFinalizeFunctionPassManager(self.as_raw());
    }
}

impl<'mid, 'module, 'fpm> InitializedFunctionPassManager<'mid, 'module, 'fpm> {
    pub fn run<'cid>(&mut self, function: &mut Function<'cid, 'mid>) {
        unsafe {
            LLVMRunFunctionPassManager(self.as_raw(), function.as_raw());
        }
    }

    pub fn as_raw(&self) -> LLVMPassManagerRef {
        self as *const InitializedFunctionPassManager as *mut InitializedFunctionPassManager as LLVMPassManagerRef
    }
}
<commit_msg>Fix mem2reg to not use reg2mem<commit_after>use std::marker::PhantomData;

use id::IdRef;
use owned::{DropInPlace, Owned};

use llvm_sys::prelude::LLVMPassManagerRef;
use llvm_sys::core::{LLVMCreateFunctionPassManagerForModule, LLVMDisposePassManager};
use llvm_sys::core::{LLVMInitializeFunctionPassManager, LLVMFinalizeFunctionPassManager};
use llvm_sys::core::LLVMRunFunctionPassManager;
use llvm_sys::transforms::scalar::{
    LLVMAddBasicAliasAnalysisPass,
    LLVMAddGVNPass,
    LLVMAddInstructionCombiningPass,
    LLVMAddPromoteMemoryToRegisterPass,
    LLVMAddReassociatePass,
    LLVMAddCFGSimplificationPass
};

use llvm::{Function, Module, ModuleBuilder};

pub struct FunctionPassManager<'mid> {
    _module_id: IdRef<'mid>
}

impl<'mid> DropInPlace for FunctionPassManager<'mid> {
    unsafe fn drop_in_place(&mut self) {
        LLVMDisposePassManager(self.as_raw());
    }
}

impl<'mid> FunctionPassManager<'mid> {
    pub fn new<'cid, 'context>(module: &Module<'cid, 'context, 'mid>) -> Owned<FunctionPassManager<'mid>> {
        unsafe {
            Owned::from_raw(LLVMCreateFunctionPassManagerForModule(module.as_raw()) as *mut FunctionPassManager)
        }
    }

    pub fn add_basic_alias_analysis(&mut self) {
        unsafe {
            LLVMAddBasicAliasAnalysisPass(self.as_raw());
        }
    }

    pub fn add_gvn(&mut self) {
        unsafe {
            LLVMAddGVNPass(self.as_raw());
        }
    }

    pub fn add_instruction_combine(&mut self) {
        unsafe {
            LLVMAddInstructionCombiningPass(self.as_raw());
        }
    }

    pub fn add_memory_to_register(&mut self) {
        unsafe {
            LLVMAddPromoteMemoryToRegisterPass(self.as_raw());
        }
    }

    pub fn add_reassociate(&mut self) {
        unsafe {
            LLVMAddReassociatePass(self.as_raw());
        }
    }

    pub fn add_simplify_cfg(&mut self) {
        unsafe {
            LLVMAddCFGSimplificationPass(self.as_raw());
        }
    }

    pub fn initialize<'fpm, 'cid, 'module>(&'fpm mut self, _module: &ModuleBuilder<'cid, 'mid, 'module>) -> Owned<InitializedFunctionPassManager<'mid, 'module, 'fpm>> {
        unsafe {
            LLVMInitializeFunctionPassManager(self.as_raw());
            Owned::from_raw(self.as_raw() as *mut InitializedFunctionPassManager)
        }
    }

    pub fn as_raw(&self) -> LLVMPassManagerRef {
        self as *const FunctionPassManager as *mut FunctionPassManager as LLVMPassManagerRef
    }
}

pub struct InitializedFunctionPassManager<'mid: 'module + 'fpm, 'module, 'fpm> {
    _marker: PhantomData<(&'module mut Module<'static, 'static, 'mid>, &'fpm mut FunctionPassManager<'mid>)>
}

impl<'mid, 'module, 'fpm> DropInPlace for InitializedFunctionPassManager<'mid, 'module, 'fpm> {
    unsafe fn drop_in_place(&mut self) {
        LLVMFinalizeFunctionPassManager(self.as_raw());
    }
}

impl<'mid, 'module, 'fpm> InitializedFunctionPassManager<'mid, 'module, 'fpm> {
    pub fn run<'cid>(&mut self, function: &mut Function<'cid, 'mid>) {
        unsafe {
            LLVMRunFunctionPassManager(self.as_raw(), function.as_raw());
        }
    }

    pub fn as_raw(&self) -> LLVMPassManagerRef {
        self as *const InitializedFunctionPassManager as *mut InitializedFunctionPassManager as LLVMPassManagerRef
    }
}
<|endoftext|>


<commit_before>use byteorder::{ReadBytesExt, LittleEndian};
use lnkpkg::errors::{LnkError};
use lnkpkg::utils;
use rwinstructs::guid::{Guid};
use std::io::SeekFrom;
use std::io::Read;
use std::io::Seek;

#[derive(Serialize,Debug)]
pub struct ShimLayerProperties {
    name: String,
}
impl ShimLayerProperties {
    pub fn new<R: Read>(mut reader: R) -> Result<ShimLayerProperties,LnkError> {
        let name = utils::read_string_u16_till_null(reader)?;

        Ok (
            ShimLayerProperties {
                name: name
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct KnownFolderLocation {
    folder_guid: Guid,
    first_child_segment_offset: u32
}
impl KnownFolderLocation {
    pub fn new<R: Read>(mut reader: R) -> Result<KnownFolderLocation,LnkError> {
        let folder_guid = Guid::new(&mut reader)?;
        let first_child_segment_offset = reader.read_u32::<LittleEndian>()?;

        Ok (
            KnownFolderLocation {
                folder_guid: folder_guid,
                first_child_segment_offset: first_child_segment_offset
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct IconLocation {
    icon_location: String,
    icon_location_unicode: String,
}
impl IconLocation {
    pub fn new<R: Read>(mut reader: R) -> Result<IconLocation,LnkError> {
        let mut icon_location_buffer = vec![0; 260];
        reader.read_exact(icon_location_buffer.as_mut_slice())?;
        let icon_location = utils::read_string_u8_till_null(
            icon_location_buffer.as_slice()
        )?;

        let mut icon_location_unicode_buffer = vec![0; 520];
        reader.read_exact(icon_location_unicode_buffer.as_mut_slice())?;
        let icon_location_unicode = utils::read_string_u8_till_null(
            icon_location_unicode_buffer.as_slice()
        )?;

        Ok (
            IconLocation {
                icon_location: icon_location,
                icon_location_unicode: icon_location_unicode
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct DarwinProperties {
    darwin_app_id: String,
    darwin_app_id_unicode: String
}
impl DarwinProperties {
    pub fn new<R: Read>(mut reader: R) -> Result<DarwinProperties,LnkError> {
        let mut darwin_app_id_buffer = vec![0; 260];
        reader.read_exact(darwin_app_id_buffer.as_mut_slice())?;
        let darwin_app_id = utils::read_string_u8_till_null(
            darwin_app_id_buffer.as_slice()
        )?;

        let mut darwin_app_id_unicode_buffer = vec![0; 520];
        reader.read_exact(darwin_app_id_unicode_buffer.as_mut_slice())?;
        let darwin_app_id_unicode = utils::read_string_u8_till_null(
            darwin_app_id_unicode_buffer.as_slice()
        )?;

        Ok (
            DarwinProperties {
                darwin_app_id: darwin_app_id,
                darwin_app_id_unicode: darwin_app_id_unicode
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct SpecialFolder {
    special_folder_id: u32,
    first_child_segment_offset: u32
}
impl SpecialFolder {
    pub fn new<R: Read>(mut reader: R) -> Result<SpecialFolder,LnkError> {
        let special_folder_id = reader.read_u32::<LittleEndian>()?;
        let first_child_segment_offset = reader.read_u32::<LittleEndian>()?;

        Ok (
            SpecialFolder {
                special_folder_id: special_folder_id,
                first_child_segment_offset: first_child_segment_offset
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct Codepage {
    codepage: u32
}
impl Codepage {
    pub fn new<R: Read>(mut reader: R) -> Result<Codepage,LnkError> {
        let codepage = reader.read_u32::<LittleEndian>()?;

        Ok (
            Codepage {
                codepage: codepage
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct DistributedTracker {
    size: u32,
    version: u32,
    machine_id: String, // 16 bytes (ascii)
    droid_volume: Guid,
    droid_file: Guid,
    birth_droid_volume: Guid,
    birth_droid_file: Guid
}
impl DistributedTracker {
    pub fn new<R: Read>(mut reader: R) -> Result<DistributedTracker,LnkError> {
        let size = reader.read_u32::<LittleEndian>()?;
        let version = reader.read_u32::<LittleEndian>()?;

        let mut buff_machine_id = vec![0; 16];
        reader.read_exact(buff_machine_id.as_mut_slice())?;
        let machine_id = utils::read_string_u8_till_null(
            buff_machine_id.as_slice()
        )?;

        let droid_volume = Guid::new(&mut reader)?;
        let droid_file = Guid::new(&mut reader)?;
        let birth_droid_volume = Guid::new(&mut reader)?;
        let birth_droid_file = Guid::new(&mut reader)?;

        Ok (
            DistributedTracker {
                size: size,
                version: version,
                machine_id: machine_id,
                droid_volume: droid_volume,
                droid_file: droid_file,
                birth_droid_volume: birth_droid_volume,
                birth_droid_file: birth_droid_file
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct EnvironmentVars {
    location: String, //size is 260 bytes (Unicode string terminated by an end-of-string character)
    location_unicode: String //size is 520 bytes (Unicode string terminated by an end-of-string character)
}
impl EnvironmentVars {
    pub fn new<R: Read>(mut reader: R) -> Result<EnvironmentVars,LnkError> {
        let mut buff_location = vec![0; 260];
        reader.read_exact(buff_location.as_mut_slice())?;
        let location = utils::read_string_u8_till_null(
            buff_location.as_slice()
        )?;

        let mut buff_location_unicode = vec![0; 520];
        reader.read_exact(buff_location_unicode.as_mut_slice())?;
        let location_unicode = utils::read_string_u16_till_null(
            buff_location_unicode.as_slice()
        )?;

        Ok(
            EnvironmentVars {
                location: location,
                location_unicode: location_unicode
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct ConsoleProperties {
    color_flags: u16,
    popup_attribs: u16,
    screen_width_buff_size: u16,
    screen_height_buff_size: u16,
    window_width: u16,
    window_height: u16,
    window_x: u16,
    window_y: u16,
    unknown1: u32,
    unknown2: u32,
    font_size: u32,
    font_family_value: u32,
    font_weight: u32,
    face_name: String, //size is 64 bytes (Unicode string terminated by an end-of-string character)
    cursor_size: u32,
    full_screen: u32,
    insert_mode: u32,
    auto_positioning: u32,
    history_buff_size: u32,
    history_buff_count: u32,
    duplicates_allowed: u32,
    color_table: utils::ByteArray
}
impl ConsoleProperties {
    pub fn new<R: Read>(mut reader: R) -> Result<ConsoleProperties,LnkError> {
        let color_flags = reader.read_u16::<LittleEndian>()?;
        let popup_attribs = reader.read_u16::<LittleEndian>()?;
        let screen_width_buff_size = reader.read_u16::<LittleEndian>()?;
        let screen_height_buff_size = reader.read_u16::<LittleEndian>()?;
        let window_width = reader.read_u16::<LittleEndian>()?;
        let window_height = reader.read_u16::<LittleEndian>()?;
        let window_x = reader.read_u16::<LittleEndian>()?;
        let window_y = reader.read_u16::<LittleEndian>()?;
        let unknown1 = reader.read_u32::<LittleEndian>()?;
        let unknown2 = reader.read_u32::<LittleEndian>()?;
        let font_size = reader.read_u32::<LittleEndian>()?;
        let font_family_value = reader.read_u32::<LittleEndian>()?;
        let font_weight = reader.read_u32::<LittleEndian>()?;

        // Read string
        let mut face_buff = vec![0; 64];
        reader.read_exact(face_buff.as_mut_slice())?;
        let face_name = utils::read_string_u16_till_null(face_buff.as_slice())?;

        let cursor_size = reader.read_u32::<LittleEndian>()?;
        let full_screen = reader.read_u32::<LittleEndian>()?;
        let insert_mode = reader.read_u32::<LittleEndian>()?;
        let auto_positioning = reader.read_u32::<LittleEndian>()?;
        let history_buff_size = reader.read_u32::<LittleEndian>()?;
        let history_buff_count = reader.read_u32::<LittleEndian>()?;
        let duplicates_allowed = reader.read_u32::<LittleEndian>()?;

        let mut color_buff = vec![0; 64];
        reader.read_exact(color_buff.as_mut_slice())?;
        let color_table = utils::ByteArray(color_buff);

        Ok (
            ConsoleProperties {
                color_flags: color_flags,
                popup_attribs: popup_attribs,
                screen_width_buff_size: screen_width_buff_size,
                screen_height_buff_size: screen_height_buff_size,
                window_width: window_width,
                window_height: window_height,
                window_x: window_x,
                window_y: window_y,
                unknown1: unknown1,
                unknown2: unknown2,
                font_size: font_size,
                font_family_value: font_family_value,
                font_weight: font_weight,
                face_name: face_name,
                cursor_size: cursor_size,
                full_screen: full_screen,
                insert_mode: insert_mode,
                auto_positioning: auto_positioning,
                history_buff_size: history_buff_size,
                history_buff_count: history_buff_count,
                duplicates_allowed: duplicates_allowed,
                color_table: color_table
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct ExtraDataBlocks {
    pub console_properties: Option<ConsoleProperties>,
    pub environment_vars: Option<EnvironmentVars>,
    pub distributed_tracker: Option<DistributedTracker>,
    pub codepage: Option<Codepage>,
    pub special_folder: Option<SpecialFolder>,
    pub darwin_properties: Option<DarwinProperties>,
    pub icon_location: Option<IconLocation>,
    pub shim_layer: Option<ShimLayerProperties>,
    pub known_folder: Option<KnownFolderLocation>
}
impl ExtraDataBlocks {
    pub fn new<Rs: Read+Seek>(mut reader: Rs) -> Result<ExtraDataBlocks,LnkError> {
        let mut console_properties = None;
        let mut environment_vars = None;
        let mut distributed_tracker = None;
        let mut codepage = None;
        let mut special_folder = None;
        let mut darwin_properties = None;
        let mut icon_location = None;
        let mut known_folder = None;
        let mut shim_layer = None;

        let mut _offset = reader.seek(
            SeekFrom::Current(0)
        )?;

        loop {
            let size = reader.read_u32::<LittleEndian>()?;
            if size != 0 {
                let signature = reader.read_u32::<LittleEndian>()?;
                match signature {
                    0xa0000001 => {
                        environment_vars = Some(EnvironmentVars::new(&mut reader)?);
                    },
                    0xa0000002 => {
                        console_properties = Some(ConsoleProperties::new(&mut reader)?);
                    },
                    0xa0000003 => {
                        distributed_tracker = Some(DistributedTracker::new(&mut reader)?);
                    },
                    0xa0000004 => {
                        codepage = Some(Codepage::new(&mut reader)?);
                    },
                    0xa0000005 => {
                        special_folder = Some(SpecialFolder::new(&mut reader)?);
                    },
                    0xa0000006 => {
                        darwin_properties = Some(DarwinProperties::new(&mut reader)?);
                    },
                    0xa0000007 => {
                        icon_location = Some(IconLocation::new(&mut reader)?);
                    },
                    0xa0000008 => {
                        shim_layer = Some(ShimLayerProperties::new(&mut reader)?);
                    },
                    0xa000000b => {
                        known_folder = Some(KnownFolderLocation::new(&mut reader)?);
                    },
                    _ => {
                        println!(
                            "Unhandled data block with signature {} at offset {}",
                            signature,
                            _offset
                        );
                    }
                }

                _offset += size as u64;

                reader.seek(
                    SeekFrom::Start(_offset)
                )?;
            } else {
                break
            }
        }

        Ok(
            ExtraDataBlocks {
                console_properties: console_properties,
                environment_vars: environment_vars,
                distributed_tracker: distributed_tracker,
                codepage: codepage,
                special_folder: special_folder,
                darwin_properties: darwin_properties,
                icon_location: icon_location,
                shim_layer: shim_layer,
                known_folder: known_folder
            }
        )
    }
}
<commit_msg>Added unhandled blocks and better json serialization of ExtraDataBlocks fields<commit_after>use byteorder::{ReadBytesExt, LittleEndian};
use lnkpkg::errors::{LnkError};
use lnkpkg::utils;
use rwinstructs::guid::{Guid};
use std::io::SeekFrom;
use std::io::Read;
use std::io::Seek;

#[derive(Serialize,Debug)]
pub struct ShimLayerProperties {
    name: String,
}
impl ShimLayerProperties {
    pub fn new<R: Read>(mut reader: R) -> Result<ShimLayerProperties,LnkError> {
        let name = utils::read_string_u16_till_null(reader)?;

        Ok (
            ShimLayerProperties {
                name: name
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct KnownFolderLocation {
    folder_guid: Guid,
    first_child_segment_offset: u32
}
impl KnownFolderLocation {
    pub fn new<R: Read>(mut reader: R) -> Result<KnownFolderLocation,LnkError> {
        let folder_guid = Guid::new(&mut reader)?;
        let first_child_segment_offset = reader.read_u32::<LittleEndian>()?;

        Ok (
            KnownFolderLocation {
                folder_guid: folder_guid,
                first_child_segment_offset: first_child_segment_offset
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct IconLocation {
    icon_location: String,
    icon_location_unicode: String,
}
impl IconLocation {
    pub fn new<R: Read>(mut reader: R) -> Result<IconLocation,LnkError> {
        let mut icon_location_buffer = vec![0; 260];
        reader.read_exact(icon_location_buffer.as_mut_slice())?;
        let icon_location = utils::read_string_u8_till_null(
            icon_location_buffer.as_slice()
        )?;

        let mut icon_location_unicode_buffer = vec![0; 520];
        reader.read_exact(icon_location_unicode_buffer.as_mut_slice())?;
        let icon_location_unicode = utils::read_string_u8_till_null(
            icon_location_unicode_buffer.as_slice()
        )?;

        Ok (
            IconLocation {
                icon_location: icon_location,
                icon_location_unicode: icon_location_unicode
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct DarwinProperties {
    darwin_app_id: String,
    darwin_app_id_unicode: String
}
impl DarwinProperties {
    pub fn new<R: Read>(mut reader: R) -> Result<DarwinProperties,LnkError> {
        let mut darwin_app_id_buffer = vec![0; 260];
        reader.read_exact(darwin_app_id_buffer.as_mut_slice())?;
        let darwin_app_id = utils::read_string_u8_till_null(
            darwin_app_id_buffer.as_slice()
        )?;

        let mut darwin_app_id_unicode_buffer = vec![0; 520];
        reader.read_exact(darwin_app_id_unicode_buffer.as_mut_slice())?;
        let darwin_app_id_unicode = utils::read_string_u8_till_null(
            darwin_app_id_unicode_buffer.as_slice()
        )?;

        Ok (
            DarwinProperties {
                darwin_app_id: darwin_app_id,
                darwin_app_id_unicode: darwin_app_id_unicode
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct SpecialFolder {
    special_folder_id: u32,
    first_child_segment_offset: u32
}
impl SpecialFolder {
    pub fn new<R: Read>(mut reader: R) -> Result<SpecialFolder,LnkError> {
        let special_folder_id = reader.read_u32::<LittleEndian>()?;
        let first_child_segment_offset = reader.read_u32::<LittleEndian>()?;

        Ok (
            SpecialFolder {
                special_folder_id: special_folder_id,
                first_child_segment_offset: first_child_segment_offset
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct Codepage {
    codepage: u32
}
impl Codepage {
    pub fn new<R: Read>(mut reader: R) -> Result<Codepage,LnkError> {
        let codepage = reader.read_u32::<LittleEndian>()?;

        Ok (
            Codepage {
                codepage: codepage
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct DistributedTracker {
    size: u32,
    version: u32,
    machine_id: String, // 16 bytes (ascii)
    droid_volume: Guid,
    droid_file: Guid,
    birth_droid_volume: Guid,
    birth_droid_file: Guid
}
impl DistributedTracker {
    pub fn new<R: Read>(mut reader: R) -> Result<DistributedTracker,LnkError> {
        let size = reader.read_u32::<LittleEndian>()?;
        let version = reader.read_u32::<LittleEndian>()?;

        let mut buff_machine_id = vec![0; 16];
        reader.read_exact(buff_machine_id.as_mut_slice())?;
        let machine_id = utils::read_string_u8_till_null(
            buff_machine_id.as_slice()
        )?;

        let droid_volume = Guid::new(&mut reader)?;
        let droid_file = Guid::new(&mut reader)?;
        let birth_droid_volume = Guid::new(&mut reader)?;
        let birth_droid_file = Guid::new(&mut reader)?;

        Ok (
            DistributedTracker {
                size: size,
                version: version,
                machine_id: machine_id,
                droid_volume: droid_volume,
                droid_file: droid_file,
                birth_droid_volume: birth_droid_volume,
                birth_droid_file: birth_droid_file
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct EnvironmentVars {
    location: String, //size is 260 bytes (Unicode string terminated by an end-of-string character)
    location_unicode: String //size is 520 bytes (Unicode string terminated by an end-of-string character)
}
impl EnvironmentVars {
    pub fn new<R: Read>(mut reader: R) -> Result<EnvironmentVars,LnkError> {
        let mut buff_location = vec![0; 260];
        reader.read_exact(buff_location.as_mut_slice())?;
        let location = utils::read_string_u8_till_null(
            buff_location.as_slice()
        )?;

        let mut buff_location_unicode = vec![0; 520];
        reader.read_exact(buff_location_unicode.as_mut_slice())?;
        let location_unicode = utils::read_string_u16_till_null(
            buff_location_unicode.as_slice()
        )?;

        Ok(
            EnvironmentVars {
                location: location,
                location_unicode: location_unicode
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct ConsoleProperties {
    color_flags: u16,
    popup_attribs: u16,
    screen_width_buff_size: u16,
    screen_height_buff_size: u16,
    window_width: u16,
    window_height: u16,
    window_x: u16,
    window_y: u16,
    unknown1: u32,
    unknown2: u32,
    font_size: u32,
    font_family_value: u32,
    font_weight: u32,
    face_name: String, //size is 64 bytes (Unicode string terminated by an end-of-string character)
    cursor_size: u32,
    full_screen: u32,
    insert_mode: u32,
    auto_positioning: u32,
    history_buff_size: u32,
    history_buff_count: u32,
    duplicates_allowed: u32,
    color_table: utils::ByteArray
}
impl ConsoleProperties {
    pub fn new<R: Read>(mut reader: R) -> Result<ConsoleProperties,LnkError> {
        let color_flags = reader.read_u16::<LittleEndian>()?;
        let popup_attribs = reader.read_u16::<LittleEndian>()?;
        let screen_width_buff_size = reader.read_u16::<LittleEndian>()?;
        let screen_height_buff_size = reader.read_u16::<LittleEndian>()?;
        let window_width = reader.read_u16::<LittleEndian>()?;
        let window_height = reader.read_u16::<LittleEndian>()?;
        let window_x = reader.read_u16::<LittleEndian>()?;
        let window_y = reader.read_u16::<LittleEndian>()?;
        let unknown1 = reader.read_u32::<LittleEndian>()?;
        let unknown2 = reader.read_u32::<LittleEndian>()?;
        let font_size = reader.read_u32::<LittleEndian>()?;
        let font_family_value = reader.read_u32::<LittleEndian>()?;
        let font_weight = reader.read_u32::<LittleEndian>()?;

        // Read string
        let mut face_buff = vec![0; 64];
        reader.read_exact(face_buff.as_mut_slice())?;
        let face_name = utils::read_string_u16_till_null(face_buff.as_slice())?;

        let cursor_size = reader.read_u32::<LittleEndian>()?;
        let full_screen = reader.read_u32::<LittleEndian>()?;
        let insert_mode = reader.read_u32::<LittleEndian>()?;
        let auto_positioning = reader.read_u32::<LittleEndian>()?;
        let history_buff_size = reader.read_u32::<LittleEndian>()?;
        let history_buff_count = reader.read_u32::<LittleEndian>()?;
        let duplicates_allowed = reader.read_u32::<LittleEndian>()?;

        let mut color_buff = vec![0; 64];
        reader.read_exact(color_buff.as_mut_slice())?;
        let color_table = utils::ByteArray(color_buff);

        Ok (
            ConsoleProperties {
                color_flags: color_flags,
                popup_attribs: popup_attribs,
                screen_width_buff_size: screen_width_buff_size,
                screen_height_buff_size: screen_height_buff_size,
                window_width: window_width,
                window_height: window_height,
                window_x: window_x,
                window_y: window_y,
                unknown1: unknown1,
                unknown2: unknown2,
                font_size: font_size,
                font_family_value: font_family_value,
                font_weight: font_weight,
                face_name: face_name,
                cursor_size: cursor_size,
                full_screen: full_screen,
                insert_mode: insert_mode,
                auto_positioning: auto_positioning,
                history_buff_size: history_buff_size,
                history_buff_count: history_buff_count,
                duplicates_allowed: duplicates_allowed,
                color_table: color_table
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct UnhandledDataBlock {
    signature: String,
    buffer: utils::ByteArray
}

#[derive(Serialize,Debug)]
pub struct ExtraDataBlocks {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub console_properties: Option<ConsoleProperties>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub environment_vars: Option<EnvironmentVars>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub distributed_tracker: Option<DistributedTracker>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub codepage: Option<Codepage>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub special_folder: Option<SpecialFolder>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub darwin_properties: Option<DarwinProperties>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub icon_location: Option<IconLocation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub shim_layer: Option<ShimLayerProperties>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub known_folder: Option<KnownFolderLocation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub unhandled_blocks: Option<Vec<UnhandledDataBlock>>
}
impl ExtraDataBlocks {
    pub fn new<Rs: Read+Seek>(mut reader: Rs) -> Result<ExtraDataBlocks,LnkError> {
        let mut console_properties = None;
        let mut environment_vars = None;
        let mut distributed_tracker = None;
        let mut codepage = None;
        let mut special_folder = None;
        let mut darwin_properties = None;
        let mut icon_location = None;
        let mut known_folder = None;
        let mut shim_layer = None;
        let mut unhandled_blocks = None;

        let mut _offset = reader.seek(
            SeekFrom::Current(0)
        )?;

        loop {
            let size = reader.read_u32::<LittleEndian>()?;
            if size != 0 {
                let signature = reader.read_u32::<LittleEndian>()?;
                match signature {
                    0xa0000001 => {
                        environment_vars = Some(EnvironmentVars::new(&mut reader)?);
                    },
                    0xa0000002 => {
                        console_properties = Some(ConsoleProperties::new(&mut reader)?);
                    },
                    0xa0000003 => {
                        distributed_tracker = Some(DistributedTracker::new(&mut reader)?);
                    },
                    0xa0000004 => {
                        codepage = Some(Codepage::new(&mut reader)?);
                    },
                    0xa0000005 => {
                        special_folder = Some(SpecialFolder::new(&mut reader)?);
                    },
                    0xa0000006 => {
                        darwin_properties = Some(DarwinProperties::new(&mut reader)?);
                    },
                    0xa0000007 => {
                        icon_location = Some(IconLocation::new(&mut reader)?);
                    },
                    0xa0000008 => {
                        shim_layer = Some(ShimLayerProperties::new(&mut reader)?);
                    },
                    0xa000000b => {
                        known_folder = Some(KnownFolderLocation::new(&mut reader)?);
                    },
                    _ => {
                        let mut unknown_block_buffer = vec![0; size as usize];
                        reader.read_exact(unknown_block_buffer.as_mut_slice())?;
                        let unknown_block = UnhandledDataBlock {
                            signature: format!("0x{:04X}",signature),
                            buffer: utils::ByteArray(unknown_block_buffer)
                        };

                        if unhandled_blocks.is_some() {
                            // unhandled_blocks.as_mut().unwrap().push(unknown_block);
                            let mut x: &mut Vec<UnhandledDataBlock> = unhandled_blocks.as_mut().unwrap();
                            x.push(unknown_block);
                        } else {
                            unhandled_blocks = Some(Vec::new());
                            unhandled_blocks.as_mut().unwrap().push(unknown_block);
                        }

                        warn!(
                            "Unhandled data block with signature {} at offset {}",
                            format!("0x{:04X}",signature),
                            _offset
                        );
                    }
                }

                _offset += size as u64;

                reader.seek(
                    SeekFrom::Start(_offset)
                )?;
            } else {
                break
            }
        }

        Ok(
            ExtraDataBlocks {
                console_properties: console_properties,
                environment_vars: environment_vars,
                distributed_tracker: distributed_tracker,
                codepage: codepage,
                special_folder: special_folder,
                darwin_properties: darwin_properties,
                icon_location: icon_location,
                shim_layer: shim_layer,
                known_folder: known_folder,
                unhandled_blocks: unhandled_blocks
            }
        )
    }
}
<|endoftext|>


<commit_before>#![crate_name = "foo"]

#![unstable(feature = "humans",
            reason = "who ever let humans program computers, we're apparently really bad at it",
            issue = "none")]

#![feature(foo, foo2)]
#![feature(staged_api)]

// @has 'foo/fn.foo.html' '//pre' 'pub unsafe fn foo() -> u32'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
pub const unsafe fn foo() -> u32 { 42 }

// @has 'foo/fn.foo2.html' '//pre' 'pub fn foo2() -> u32'
#[unstable(feature = "humans", issue = "none")]
pub const fn foo2() -> u32 { 42 }

// @has 'foo/fn.bar2.html' '//pre' 'pub const fn bar2() -> u32'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
pub const fn bar2() -> u32 { 42 }

// @has 'foo/fn.foo2_gated.html' '//pre' 'pub unsafe fn foo2_gated() -> u32'
#[unstable(feature = "foo2", issue = "none")]
pub const unsafe fn foo2_gated() -> u32 { 42 }

// @has 'foo/fn.bar2_gated.html' '//pre' 'pub const unsafe fn bar2_gated() -> u32'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
pub const unsafe fn bar2_gated() -> u32 { 42 }

// @has 'foo/fn.bar_not_gated.html' '//pre' 'pub unsafe fn bar_not_gated() -> u32'
pub const unsafe fn bar_not_gated() -> u32 { 42 }
<commit_msg>Add test for rustc_const_unstable on methods<commit_after>#![crate_name = "foo"]

#![unstable(feature = "humans",
            reason = "who ever let humans program computers, we're apparently really bad at it",
            issue = "none")]

#![feature(foo, foo2)]
#![feature(staged_api)]

// @has 'foo/fn.foo.html' '//pre' 'pub unsafe fn foo() -> u32'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
pub const unsafe fn foo() -> u32 { 42 }

// @has 'foo/fn.foo2.html' '//pre' 'pub fn foo2() -> u32'
#[unstable(feature = "humans", issue = "none")]
pub const fn foo2() -> u32 { 42 }

// @has 'foo/fn.bar2.html' '//pre' 'pub const fn bar2() -> u32'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
pub const fn bar2() -> u32 { 42 }

// @has 'foo/fn.foo2_gated.html' '//pre' 'pub unsafe fn foo2_gated() -> u32'
#[unstable(feature = "foo2", issue = "none")]
pub const unsafe fn foo2_gated() -> u32 { 42 }

// @has 'foo/fn.bar2_gated.html' '//pre' 'pub const unsafe fn bar2_gated() -> u32'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
pub const unsafe fn bar2_gated() -> u32 { 42 }

// @has 'foo/fn.bar_not_gated.html' '//pre' 'pub unsafe fn bar_not_gated() -> u32'
pub const unsafe fn bar_not_gated() -> u32 { 42 }

pub struct Foo;

impl Foo {
    // @has 'foo/struct.Foo.html' '//h4[@id="method.gated"]/code' 'pub unsafe fn gated() -> u32'
    #[stable(feature = "rust1", since = "1.0.0")]
    #[rustc_const_unstable(feature="foo", issue = "none")]
    pub const unsafe fn gated() -> u32 { 42 }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "nightly-testing", plugin(clippy))]
#![cfg_attr(feature = "nightly-testing", feature(plugin))]
#![cfg_attr(feature = "nightly-testing", allow(too_many_arguments))]
#![cfg_attr(feature = "nightly-testing", allow(used_underscore_binding))]
#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))]
#![cfg_attr(not(feature = "with-syntex"), plugin(quasi_macros))]

extern crate aster;
extern crate quasi;

#[cfg(feature = "with-syntex")]
extern crate syntex;

#[cfg(feature = "with-syntex")]
#[macro_use]
extern crate syntex_syntax as syntax;

#[cfg(not(feature = "with-syntex"))]
#[macro_use]
extern crate syntax;

#[cfg(not(feature = "with-syntex"))]
extern crate rustc_plugin;

#[cfg(not(feature = "with-syntex"))]
use syntax::feature_gate::AttributeType;

#[cfg(feature = "with-syntex")]
include!(concat!(env!("OUT_DIR"), "/lib.rs"));

#[cfg(not(feature = "with-syntex"))]
include!("lib.rs.in");

#[cfg(feature = "with-syntex")]
pub fn register(reg: &mut syntex::Registry) {
    use syntax::{ast, fold};

    /// Strip the serde attributes from the crate.
    #[cfg(feature = "with-syntex")]
    fn strip_attributes(krate: ast::Crate) -> ast::Crate {
        /// Helper folder that strips the serde attributes after the extensions have been expanded.
        struct StripAttributeFolder;

        impl fold::Folder for StripAttributeFolder {
            fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
                match attr.node.value.node {
                    ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; }
                    _ => {}
                }

                Some(attr)
            }

            fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
                fold::noop_fold_mac(mac, self)
            }
        }

        fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
    }

    reg.add_attr("feature(custom_derive)");
    reg.add_attr("feature(custom_attribute)");

    reg.add_decorator("derive_Serialize", ser::expand_derive_serialize);
    reg.add_decorator("derive_Deserialize", de::expand_derive_deserialize);

    reg.add_post_expansion_pass(strip_attributes);
}

#[cfg(not(feature = "with-syntex"))]
pub fn register(reg: &mut rustc_plugin::Registry) {
    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_Serialize"),
        syntax::ext::base::MultiDecorator(
            Box::new(ser::expand_derive_serialize)));

    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_Deserialize"),
        syntax::ext::base::MultiDecorator(
            Box::new(de::expand_derive_deserialize)));

    reg.register_attribute("serde".to_owned(), AttributeType::Normal);
}
<commit_msg>Disable clippy lint "useless_let_if_seq"<commit_after>#![cfg_attr(feature = "nightly-testing", plugin(clippy))]
#![cfg_attr(feature = "nightly-testing", feature(plugin))]
#![cfg_attr(feature = "nightly-testing", allow(too_many_arguments))]
#![cfg_attr(feature = "nightly-testing", allow(used_underscore_binding))]
#![cfg_attr(feature = "nightly-testing", allow(useless_let_if_seq))]
#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))]
#![cfg_attr(not(feature = "with-syntex"), plugin(quasi_macros))]

extern crate aster;
extern crate quasi;

#[cfg(feature = "with-syntex")]
extern crate syntex;

#[cfg(feature = "with-syntex")]
#[macro_use]
extern crate syntex_syntax as syntax;

#[cfg(not(feature = "with-syntex"))]
#[macro_use]
extern crate syntax;

#[cfg(not(feature = "with-syntex"))]
extern crate rustc_plugin;

#[cfg(not(feature = "with-syntex"))]
use syntax::feature_gate::AttributeType;

#[cfg(feature = "with-syntex")]
include!(concat!(env!("OUT_DIR"), "/lib.rs"));

#[cfg(not(feature = "with-syntex"))]
include!("lib.rs.in");

#[cfg(feature = "with-syntex")]
pub fn register(reg: &mut syntex::Registry) {
    use syntax::{ast, fold};

    /// Strip the serde attributes from the crate.
    #[cfg(feature = "with-syntex")]
    fn strip_attributes(krate: ast::Crate) -> ast::Crate {
        /// Helper folder that strips the serde attributes after the extensions have been expanded.
        struct StripAttributeFolder;

        impl fold::Folder for StripAttributeFolder {
            fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
                match attr.node.value.node {
                    ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; }
                    _ => {}
                }

                Some(attr)
            }

            fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
                fold::noop_fold_mac(mac, self)
            }
        }

        fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
    }

    reg.add_attr("feature(custom_derive)");
    reg.add_attr("feature(custom_attribute)");

    reg.add_decorator("derive_Serialize", ser::expand_derive_serialize);
    reg.add_decorator("derive_Deserialize", de::expand_derive_deserialize);

    reg.add_post_expansion_pass(strip_attributes);
}

#[cfg(not(feature = "with-syntex"))]
pub fn register(reg: &mut rustc_plugin::Registry) {
    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_Serialize"),
        syntax::ext::base::MultiDecorator(
            Box::new(ser::expand_derive_serialize)));

    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_Deserialize"),
        syntax::ext::base::MultiDecorator(
            Box::new(de::expand_derive_deserialize)));

    reg.register_attribute("serde".to_owned(), AttributeType::Normal);
}
<|endoftext|>


<commit_before>use {Type, Error};

use std::collections::HashMap;
use std::io::prelude::*;
use std;

pub type SizeType = u32;

impl<K, V> Type for HashMap<K, V>
    where K: Type + std::hash::Hash + Eq,
          V: Type
{
    fn read(read: &mut Read) -> Result<Self, Error> {
        let mut map = HashMap::new();

        let length = SizeType::read(read)?;

        for _ in 0..length {
            let key = K::read(read)?;
            let value = V::read(read)?;

            map.insert(key, value);
        }

        Ok(map)
    }

    fn write(&self, write: &mut Write) -> Result<(), Error> {
        (self.len() as SizeType).write(write)?;

        for (key, value) in self.iter() {
            key.write(write)?;
            value.write(write)?;
        }

        Ok(())
    }
}

<commit_msg>Generalize the HashMap Type implementation<commit_after>use {Type, Error};

use std::collections::{HashMap, BTreeMap};
use std::hash::Hash;

use std::io::prelude::*;

pub type SizeType = u32;

macro_rules! impl_map_type {
    ( $ty:ident => K: $( $k_pred:ident ),+ ) => {
        impl<K, V> Type for $ty<K, V>
            where K: Type + $( $k_pred +)+,
                  V: Type
        {
            fn read(read: &mut Read) -> Result<Self, Error> {
                let mut map = $ty::new();

                let length = SizeType::read(read)?;

                for _ in 0..length {
                    let key = K::read(read)?;
                    let value = V::read(read)?;

                    map.insert(key, value);
                }

                Ok(map)
            }

            fn write(&self, write: &mut Write) -> Result<(), Error> {
                (self.len() as SizeType).write(write)?;

                for (key, value) in self.iter() {
                    key.write(write)?;
                    value.write(write)?;
                }

                Ok(())
            }
        }
    }
}

impl_map_type!(HashMap => K: Hash, Eq);
impl_map_type!(BTreeMap => K: Ord);

<|endoftext|>


<commit_before>#![allow(unused)]

use super::{GS_DEFAULT_BORDER_TOL, GS_DEFAULT_TOLERANCE, SQRT_2, SQRT_3};
use crate::StrError;
use plotpy::{Canvas, Curve, Plot, Text};
use std::collections::{HashMap, HashSet};
use std::fmt;

/// Specifies the key of containers (or bins in the grid)
type ContainerKey = usize;

/// Specifies the identification number of items
type ItemID = usize;

/// Defines the container type: ID to Coordinates
type Container = HashSet<ItemID>;

/// Defines the containers type: Key to Container
type Containers = HashMap<ContainerKey, Container>;

/// Defines the bounding box of a cell
const N_MIN_MAX: usize = 2; // 2 means {min,max}
const I_MIN: usize = 0;
const I_MAX: usize = 1;
type BboxMinMax = Vec<Vec<f64>>; // [ndim][N_MIN_MAX]
type BoundingBoxes = HashMap<ItemID, BboxMinMax>;

pub struct GridSearchCell {
    ndim: usize,                   // space dimension
    ndiv: Vec<usize>,              // (ndim) number of divisions along each direction
    xmin: Vec<f64>,                // (ndim) min values
    xmax: Vec<f64>,                // (ndim) max values
    bbox_large: Vec<f64>,          // largest bounding box
    side_length: f64,              // side length of a container
    coefficient: Vec<usize>,       // (3) coefficients [1, ndiv[0], ndiv[0]*ndiv[1]] (Eq. 8)
    tol_dist: f64,                 // tolerance to find points using the distance between points
    bounding_boxes: BoundingBoxes, // bounding boxes
    containers: Containers,        // structure to hold all items
}

impl GridSearchCell {
    pub fn new<'a, F, G>(
        ndim: usize,
        ncell: usize,
        get_nnode: F,
        get_x: G,
        tolerance: Option<f64>,
        border_tol: Option<f64>,
    ) -> Result<Self, StrError>
    where
        F: Fn(usize) -> Result<usize, StrError>,
        G: Fn(usize, usize) -> Result<&'a [f64], StrError>,
    {
        // check input
        if ndim < 2 || ndim > 3 {
            return Err("ndim must be 2 or 3");
        }

        // tolerance
        let tolerance = match tolerance {
            Some(v) => v,
            None => GS_DEFAULT_TOLERANCE,
        };
        if tolerance <= 0.0 {
            return Err("tolerance must be > 0.0");
        }

        // border tolerance
        let border_tol = match border_tol {
            Some(v) => v,
            None => GS_DEFAULT_BORDER_TOL,
        };
        if border_tol < 0.0 {
            return Err("border_tol must be ≥ 0.0");
        }

        // find limits, bounding boxes, and largest cell
        let mut xmin = vec![f64::MAX; ndim];
        let mut xmax = vec![f64::MIN; ndim];
        let mut x_min_max = vec![vec![0.0; N_MIN_MAX]; ndim];
        let mut bbox_large = vec![f64::MIN; ndim];
        let mut bounding_boxes = HashMap::new();
        for c in 0..ncell {
            let nnode = get_nnode(c)?;
            for m in 0..nnode {
                let x = get_x(c, m)?;
                for i in 0..ndim {
                    // limits
                    xmin[i] = f64::min(xmin[i], x[i]);
                    xmax[i] = f64::max(xmax[i], x[i]);
                    // bounding box
                    if m == 0 {
                        for i in 0..ndim {
                            x_min_max[i][I_MIN] = x[i];
                            x_min_max[i][I_MAX] = x[i];
                        }
                    } else {
                        x_min_max[i][I_MIN] = f64::min(x_min_max[i][I_MIN], x[i]);
                        x_min_max[i][I_MAX] = f64::max(x_min_max[i][I_MAX], x[i]);
                    }
                }
            }
            // largest cell
            for i in 0..ndim {
                bbox_large[i] = f64::max(bbox_large[i], x_min_max[i][I_MAX] - x_min_max[i][I_MIN]);
            }
            // add to bounding box maps
            bounding_boxes.insert(c, x_min_max.clone());
        }

        // make the side_length equal to the largest bounding box dimension
        let mut side_length = bbox_large[0] + tolerance;
        for i in 1..ndim {
            side_length = f64::max(side_length, bbox_large[i] + tolerance);
        }

        // expand borders
        if border_tol > 0.0 {
            for i in 0..ndim {
                xmin[i] -= border_tol;
                xmax[i] += border_tol;
            }
        }

        // number of divisions
        let mut ndiv = vec![0; ndim];
        for i in 0..ndim {
            assert!(xmax[i] > xmin[i]);
            ndiv[i] = ((xmax[i] - xmin[i]) / side_length) as usize;
        }

        // update xmax after deciding on the side_length and number of divisions
        for i in 0..ndim {
            xmax[i] = xmin[i] + side_length * (ndiv[i] as f64);
        }

        // coefficient
        let coefficient = vec![1, ndiv[0], ndiv[0] * ndiv[1]];

        // tolerance to find points
        let tol_dist = if ndim == 2 {
            SQRT_2 * tolerance
        } else {
            SQRT_3 * tolerance
        };

        Ok(GridSearchCell {
            ndim,
            ndiv,
            xmin,
            xmax,
            bbox_large,
            side_length,
            coefficient,
            tol_dist,
            bounding_boxes,
            containers: HashMap::new(),
        })
    }

    /// Inserts a cell (e.g., triangle/tetrahedron) to the grid
    ///
    /// # Input
    ///
    /// * `id` -- is the id of the cell
    /// * `nnode` -- is the number of nodes of the cell
    /// * `get_x` -- is a function that returns the coordinates of a cell node
    pub fn insert_cell<'a, F>(&mut self, id: usize, nnode: usize, get_x: F) -> Result<(), StrError>
    where
        F: Fn(usize) -> Result<&'a [f64], StrError>,
    {
        // TODO
        Ok(())
    }

    /// Calculates the key of the container where the point should fall in
    ///
    /// **Note:** Returns None if the point is out-of-range
    #[inline]
    fn calc_container_key(&self, x: &[f64]) -> Option<usize> {
        let mut ratio = vec![0; self.ndim]; // ratio = trunc(δx[i]/Δx[i]) (Eq. 8)
        let mut key = 0;
        for i in 0..self.ndim {
            if x[i] < self.xmin[i] || x[i] > self.xmax[i] {
                return None;
            }
            ratio[i] = ((x[i] - self.xmin[i]) / self.side_length) as usize;
            if ratio[i] == self.ndiv[i] {
                // the point is exactly on the max edge, thus select inner container
                ratio[i] -= 1; // move to the inside
            }
            key += ratio[i] * self.coefficient[i];
        }
        Some(key)
    }

    /// Updates a container or inserts a point into an existing container
    #[inline]
    fn update_or_insert(&mut self, key: ContainerKey, id: ItemID) {
        let container = self.containers.entry(key).or_insert(HashSet::new());
        container.insert(id);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::GridSearchCell;
    use crate::util::{SQRT_2, SQRT_3};
    use crate::StrError;
    use plotpy::{Canvas, Curve, Plot, PolyCode, RayEndpoint, Surface};
    use russell_chk::{assert_approx_eq, assert_vec_approx_eq};

    #[test]
    fn insert_cell_works_2d() -> Result<(), StrError> {
        // [num_triangle][nnode=3][ndim=2]
        const TRIANGLES: [[[f64; 2]; 3]; 12] = [
            [[0.230951, 0.558482], [0.133721, 0.348832], [0.540745, 0.331184]],
            [[0.13928, 0.180603], [0.133721, 0.348832], [0.0307942, 0.459123]],
            [[0.0307942, 0.459123], [0.230951, 0.558482], [0.0980015, 0.981755]],
            [[0.230951, 0.558482], [0.0307942, 0.459123], [0.133721, 0.348832]],
            [[0.0980015, 0.981755], [0.230951, 0.558482], [0.578587, 0.760349]],
            [[0.133721, 0.348832], [0.13928, 0.180603], [0.540745, 0.331184]],
            [[0.540745, 0.331184], [0.578587, 0.760349], [0.230951, 0.558482]],
            [[0.540745, 0.331184], [0.478554, 0.00869692], [0.648071, 0.369534]],
            [[0.578587, 0.760349], [0.648071, 0.369534], [0.903726, 0.975904]],
            [[0.648071, 0.369534], [0.578587, 0.760349], [0.540745, 0.331184]],
            [[0.578587, 0.760349], [0.903726, 0.975904], [0.0980015, 0.981755]],
            [[0.540745, 0.331184], [0.13928, 0.180603], [0.478554, 0.00869692]],
        ];
        let get_nnode = |_| Ok(3);
        let get_x = |t: usize, m: usize| Ok(&TRIANGLES[t][m][..]);
        let mut grid = GridSearchCell::new(2, TRIANGLES.len(), get_nnode, get_x, None, None)?;
        println!("{:?}", grid.bbox_large);
        /*
        println!("{}", grid);
        let mut id = 0;
        for t in 0..TRIANGLES.len() {
            grid.insert_cell(id, 3, |m| Ok(&TRIANGLES[t][m]))?;
            id += 1;
        }
        assert_eq!(
            format!("{}", grid),
            "0: [100, 101]\n\
             ids = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]\n\
             nitem = 12\n\
             ncontainer = 21\n\
             ndiv = [5, 5]\n"
        );
        if false {
            let mut plot = Plot::new();
            let mut canvas = Canvas::new();
            canvas.set_face_color("#fefddc").set_edge_color("#fcb827");
            for t in 0..TRIANGLES.len() {
                canvas.polycurve_begin();
                for m in 0..3 {
                    let code = if m == 0 { PolyCode::MoveTo } else { PolyCode::LineTo };
                    canvas.polycurve_add(&TRIANGLES[t][m][0], &TRIANGLES[t][m][1], code);
                }
                canvas.polycurve_end(true);
            }
            plot.add(&canvas);
            grid.draw(&mut plot)?;
            plot.set_equal_axes(true)
                .set_figure_size_points(600.0, 600.0)
                .grid_and_labels("x", "y")
                .set_ticks_x(0.1, 0.01, "")
                .set_ticks_y(0.1, 0.01, "")
                .save("/tmp/gemlab/test_insert_cell_2d.svg")?;
        }
        */
        Ok(())
    }
}
<commit_msg>Add test<commit_after>#![allow(unused)]

use super::{GS_DEFAULT_BORDER_TOL, GS_DEFAULT_TOLERANCE, SQRT_2, SQRT_3};
use crate::StrError;
use plotpy::{Canvas, Curve, Plot, Text};
use std::collections::{HashMap, HashSet};
use std::fmt;

/// Specifies the key of containers (or bins in the grid)
type ContainerKey = usize;

/// Specifies the identification number of items
type ItemID = usize;

/// Defines the container type: ID to Coordinates
type Container = HashSet<ItemID>;

/// Defines the containers type: Key to Container
type Containers = HashMap<ContainerKey, Container>;

/// Defines the bounding box of a cell
const N_MIN_MAX: usize = 2; // 2 means {min,max}
const I_MIN: usize = 0;
const I_MAX: usize = 1;
type BboxMinMax = Vec<Vec<f64>>; // [ndim][N_MIN_MAX]
type BoundingBoxes = HashMap<ItemID, BboxMinMax>;

pub struct GridSearchCell {
    ndim: usize,                   // space dimension
    ndiv: Vec<usize>,              // (ndim) number of divisions along each direction
    xmin: Vec<f64>,                // (ndim) min values
    xmax: Vec<f64>,                // (ndim) max values
    bbox_large: Vec<f64>,          // largest bounding box
    side_length: f64,              // side length of a container
    coefficient: Vec<usize>,       // (3) coefficients [1, ndiv[0], ndiv[0]*ndiv[1]] (Eq. 8)
    tol_dist: f64,                 // tolerance to find points using the distance between points
    bounding_boxes: BoundingBoxes, // bounding boxes
    containers: Containers,        // structure to hold all items
}

impl GridSearchCell {
    pub fn new<'a, F, G>(
        ndim: usize,
        ncell: usize,
        get_nnode: F,
        get_x: G,
        tolerance: Option<f64>,
        border_tol: Option<f64>,
    ) -> Result<Self, StrError>
    where
        F: Fn(usize) -> Result<usize, StrError>,
        G: Fn(usize, usize) -> Result<&'a [f64], StrError>,
    {
        // check input
        if ndim < 2 || ndim > 3 {
            return Err("ndim must be 2 or 3");
        }

        // tolerance
        let tolerance = match tolerance {
            Some(v) => v,
            None => GS_DEFAULT_TOLERANCE,
        };
        if tolerance <= 0.0 {
            return Err("tolerance must be > 0.0");
        }

        // border tolerance
        let border_tol = match border_tol {
            Some(v) => v,
            None => GS_DEFAULT_BORDER_TOL,
        };
        if border_tol < 0.0 {
            return Err("border_tol must be ≥ 0.0");
        }

        // find limits, bounding boxes, and largest cell
        let mut xmin = vec![f64::MAX; ndim];
        let mut xmax = vec![f64::MIN; ndim];
        let mut x_min_max = vec![vec![0.0; N_MIN_MAX]; ndim];
        let mut bbox_large = vec![f64::MIN; ndim];
        let mut bounding_boxes = HashMap::new();
        for c in 0..ncell {
            let nnode = get_nnode(c)?;
            for m in 0..nnode {
                let x = get_x(c, m)?;
                for i in 0..ndim {
                    // limits
                    xmin[i] = f64::min(xmin[i], x[i]);
                    xmax[i] = f64::max(xmax[i], x[i]);
                    // bounding box
                    if m == 0 {
                        for i in 0..ndim {
                            x_min_max[i][I_MIN] = x[i];
                            x_min_max[i][I_MAX] = x[i];
                        }
                    } else {
                        x_min_max[i][I_MIN] = f64::min(x_min_max[i][I_MIN], x[i]);
                        x_min_max[i][I_MAX] = f64::max(x_min_max[i][I_MAX], x[i]);
                    }
                }
            }
            // largest cell
            for i in 0..ndim {
                bbox_large[i] = f64::max(bbox_large[i], x_min_max[i][I_MAX] - x_min_max[i][I_MIN]);
            }
            // add to bounding box maps
            bounding_boxes.insert(c, x_min_max.clone());
        }

        // make the side_length equal to the largest bounding box dimension
        let mut side_length = bbox_large[0];
        for i in 1..ndim {
            side_length = f64::max(side_length, bbox_large[i]);
        }

        // expand side_length by two times the tolerance (left and right)
        side_length += 2.0 * tolerance;

        // expand borders
        if border_tol > 0.0 {
            for i in 0..ndim {
                xmin[i] -= border_tol;
                xmax[i] += border_tol;
            }
        }

        // number of divisions
        let mut ndiv = vec![0; ndim];
        for i in 0..ndim {
            assert!(xmax[i] > xmin[i]);
            ndiv[i] = f64::ceil((xmax[i] - xmin[i]) / side_length) as usize;
        }

        // update xmax after deciding on the side_length and number of divisions
        for i in 0..ndim {
            xmax[i] = xmin[i] + side_length * (ndiv[i] as f64);
        }

        // coefficient
        let coefficient = vec![1, ndiv[0], ndiv[0] * ndiv[1]];

        // tolerance to find points
        let tol_dist = if ndim == 2 {
            SQRT_2 * tolerance
        } else {
            SQRT_3 * tolerance
        };

        Ok(GridSearchCell {
            ndim,
            ndiv,
            xmin,
            xmax,
            bbox_large,
            side_length,
            coefficient,
            tol_dist,
            bounding_boxes,
            containers: HashMap::new(),
        })
    }

    /// Inserts a cell (e.g., triangle/tetrahedron) to the grid
    ///
    /// # Input
    ///
    /// * `id` -- is the id of the cell
    /// * `nnode` -- is the number of nodes of the cell
    /// * `get_x` -- is a function that returns the coordinates of a cell node
    pub fn insert_cell<'a, F>(&mut self, id: usize, nnode: usize, get_x: F) -> Result<(), StrError>
    where
        F: Fn(usize) -> Result<&'a [f64], StrError>,
    {
        // TODO
        Ok(())
    }

    /// Calculates the key of the container where the point should fall in
    ///
    /// **Note:** Returns None if the point is out-of-range
    #[inline]
    fn calc_container_key(&self, x: &[f64]) -> Option<usize> {
        let mut ratio = vec![0; self.ndim]; // ratio = trunc(δx[i]/Δx[i]) (Eq. 8)
        let mut key = 0;
        for i in 0..self.ndim {
            if x[i] < self.xmin[i] || x[i] > self.xmax[i] {
                return None;
            }
            ratio[i] = ((x[i] - self.xmin[i]) / self.side_length) as usize;
            if ratio[i] == self.ndiv[i] {
                // the point is exactly on the max edge, thus select inner container
                ratio[i] -= 1; // move to the inside
            }
            key += ratio[i] * self.coefficient[i];
        }
        Some(key)
    }

    /// Updates a container or inserts a point into an existing container
    #[inline]
    fn update_or_insert(&mut self, key: ContainerKey, id: ItemID) {
        let container = self.containers.entry(key).or_insert(HashSet::new());
        container.insert(id);
    }
}

impl fmt::Display for GridSearchCell {
    /// Shows info about the items in the grid containers
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // items
        let mut unique_items: HashMap<usize, bool> = HashMap::new();
        let mut indices: Vec<_> = self.containers.keys().collect();
        indices.sort();
        for index in indices {
            let container = self.containers.get(index).unwrap();
            let mut ids: Vec<_> = container.iter().map(|id| *id).collect();
            ids.sort();
            write!(f, "{}: {:?}\n", index, ids).unwrap();
            for id in ids {
                unique_items.insert(id, true);
            }
        }
        // summary
        let mut ids: Vec<_> = unique_items.keys().collect();
        ids.sort();
        write!(f, "ids = {:?}\n", ids).unwrap();
        write!(f, "nitem = {}\n", unique_items.len()).unwrap();
        write!(f, "ncontainer = {}\n", self.containers.len()).unwrap();
        write!(f, "ndiv = {:?}\n", self.ndiv).unwrap();
        Ok(())
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::GridSearchCell;
    use crate::util::{SQRT_2, SQRT_3};
    use crate::StrError;
    use plotpy::{Canvas, Curve, Plot, PolyCode, RayEndpoint, Surface};
    use russell_chk::{assert_approx_eq, assert_vec_approx_eq};

    #[test]
    fn new_works() -> Result<(), StrError> {
        const TRIANGLES: [[[f64; 2]; 3]; 2] = [
            [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]],
            [[1.0, 0.0], [1.0, 1.0], [0.0, 1.0]],
        ];
        let tolerance = 1e-3;
        let border_tol = 0.1;
        let get_nnode = |_| Ok(3);
        let get_x = |t: usize, m: usize| Ok(&TRIANGLES[t][m][..]);
        let mut grid = GridSearchCell::new(2, TRIANGLES.len(), get_nnode, get_x, Some(tolerance), Some(border_tol))?;
        let max_len = 1.0;
        let side_len = max_len + 2.0 * tolerance; // because the bbox is expanded
        assert_eq!(grid.ndim, 2);
        assert_eq!(grid.side_length, side_len);
        assert_eq!(grid.ndiv, &[2, 2]);
        assert_eq!(grid.xmin, &[-0.1, -0.1]);
        assert_eq!(grid.xmax, &[-0.1 + side_len * 2.0, -0.1 + side_len * 2.0]);
        assert_eq!(grid.bbox_large, &[1.0, 1.0]);
        assert_eq!(grid.coefficient, &[1, 2, 2 * 2]);
        assert_eq!(grid.tol_dist, SQRT_2 * tolerance);
        assert_eq!(grid.bounding_boxes.len(), 2);
        assert_eq!(grid.containers.len(), 0);
        let bbox_0 = grid.bounding_boxes.get(&0).unwrap();
        let bbox_1 = grid.bounding_boxes.get(&0).unwrap();
        assert_eq!(bbox_0, &[[0.0, 1.0], [0.0, 1.0]]);
        assert_eq!(bbox_1, &[[0.0, 1.0], [0.0, 1.0]]);
        Ok(())
    }

    #[test]
    fn insert_cell_works_2d() -> Result<(), StrError> {
        // [num_triangle][nnode=3][ndim=2]
        const TRIANGLES: [[[f64; 2]; 3]; 12] = [
            [[0.230951, 0.558482], [0.133721, 0.348832], [0.540745, 0.331184]],
            [[0.13928, 0.180603], [0.133721, 0.348832], [0.0307942, 0.459123]],
            [[0.0307942, 0.459123], [0.230951, 0.558482], [0.0980015, 0.981755]],
            [[0.230951, 0.558482], [0.0307942, 0.459123], [0.133721, 0.348832]],
            [[0.0980015, 0.981755], [0.230951, 0.558482], [0.578587, 0.760349]],
            [[0.133721, 0.348832], [0.13928, 0.180603], [0.540745, 0.331184]],
            [[0.540745, 0.331184], [0.578587, 0.760349], [0.230951, 0.558482]],
            [[0.540745, 0.331184], [0.478554, 0.00869692], [0.648071, 0.369534]],
            [[0.578587, 0.760349], [0.648071, 0.369534], [0.903726, 0.975904]],
            [[0.648071, 0.369534], [0.578587, 0.760349], [0.540745, 0.331184]],
            [[0.578587, 0.760349], [0.903726, 0.975904], [0.0980015, 0.981755]],
            [[0.540745, 0.331184], [0.13928, 0.180603], [0.478554, 0.00869692]],
        ];
        let get_nnode = |_| Ok(3);
        let get_x = |t: usize, m: usize| Ok(&TRIANGLES[t][m][..]);
        let mut grid = GridSearchCell::new(2, TRIANGLES.len(), get_nnode, get_x, None, None)?;
        println!("{:?}", grid.bbox_large);
        /*
        println!("{}", grid);
        let mut id = 0;
        for t in 0..TRIANGLES.len() {
            grid.insert_cell(id, 3, |m| Ok(&TRIANGLES[t][m]))?;
            id += 1;
        }
        assert_eq!(
            format!("{}", grid),
            "0: [100, 101]\n\
             ids = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]\n\
             nitem = 12\n\
             ncontainer = 21\n\
             ndiv = [5, 5]\n"
        );
        if false {
            let mut plot = Plot::new();
            let mut canvas = Canvas::new();
            canvas.set_face_color("#fefddc").set_edge_color("#fcb827");
            for t in 0..TRIANGLES.len() {
                canvas.polycurve_begin();
                for m in 0..3 {
                    let code = if m == 0 { PolyCode::MoveTo } else { PolyCode::LineTo };
                    canvas.polycurve_add(&TRIANGLES[t][m][0], &TRIANGLES[t][m][1], code);
                }
                canvas.polycurve_end(true);
            }
            plot.add(&canvas);
            grid.draw(&mut plot)?;
            plot.set_equal_axes(true)
                .set_figure_size_points(600.0, 600.0)
                .grid_and_labels("x", "y")
                .set_ticks_x(0.1, 0.01, "")
                .set_ticks_y(0.1, 0.01, "")
                .save("/tmp/gemlab/test_insert_cell_2d.svg")?;
        }
        */
        Ok(())
    }
}
<|endoftext|>


<commit_before>use core::cmp::Eq;

pub trait Dimensional<T>: Index<uint, T> {
    static pure fn dim() -> uint;       // dim and size_of are pretty useless at the moment due to
    static pure fn size_of() -> uint;   // how Rust's static methods are currently implemented
    pure fn to_ptr() -> *T;
}<commit_msg>Remove useless import<commit_after>pub trait Dimensional<T>: Index<uint, T> {
    static pure fn dim() -> uint;       // dim and size_of are pretty useless at the moment due to
    static pure fn size_of() -> uint;   // how Rust's static methods are currently implemented
    pure fn to_ptr() -> *T;
}<|endoftext|>


<commit_before><commit_msg>seq: Adds testing for hexadecimal integer parsing<commit_after><|endoftext|>