<commit_before>use crate::array::{PyArray, PyArrayDyn};
use crate::npyffi::{
    array::PY_ARRAY_API,
    types::{NPY_CASTING, NPY_ORDER},
    *,
};
use crate::types::TypeNum;
use pyo3::{prelude::*, PyNativeType};

use std::marker::PhantomData;
use std::os::raw::*;
use std::ptr;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum NpyIterFlag {
    CIndex,
    FIndex,
    MultiIndex,
    ExternalLoop,
    CommonDtype,
    RefsOk,
    ZerosizeOk,
    ReduceOk,
    Ranged,
    Buffered,
    GrowInner,
    DelayBufAlloc,
    DontNegateStrides,
    CopyIfOverlap,
    ReadWrite,
    ReadOnly,
    WriteOnly,
}

impl NpyIterFlag {
    fn to_c_enum(&self) -> npy_uint32 {
        use NpyIterFlag::*;
        match self {
            CIndex => NPY_ITER_C_INDEX,
            FIndex => NPY_ITER_C_INDEX,
            MultiIndex => NPY_ITER_MULTI_INDEX,
            ExternalLoop => NPY_ITER_EXTERNAL_LOOP,
            CommonDtype => NPY_ITER_COMMON_DTYPE,
            RefsOk => NPY_ITER_REFS_OK,
            ZerosizeOk => NPY_ITER_ZEROSIZE_OK,
            ReduceOk => NPY_ITER_REDUCE_OK,
            Ranged => NPY_ITER_RANGED,
            Buffered => NPY_ITER_BUFFERED,
            GrowInner => NPY_ITER_GROWINNER,
            DelayBufAlloc => NPY_ITER_DELAY_BUFALLOC,
            DontNegateStrides => NPY_ITER_DONT_NEGATE_STRIDES,
            CopyIfOverlap => NPY_ITER_COPY_IF_OVERLAP,
            ReadWrite => NPY_ITER_READWRITE,
            ReadOnly => NPY_ITER_READONLY,
            WriteOnly => NPY_ITER_WRITEONLY,
        }
    }
}

pub struct NpyIterBuilder<'py, T> {
    flags: npy_uint32,
    array: &'py PyArrayDyn<T>,
}

impl<'py, T: TypeNum> NpyIterBuilder<'py, T> {
    pub fn new<D: ndarray::Dimension>(array: &'py PyArray<T, D>) -> NpyIterBuilder<'py, T> {
        NpyIterBuilder {
            flags: 0,
            array: array.into_dyn(),
        }
    }

    pub fn set(mut self, flag: NpyIterFlag) -> Self {
        if flag == NpyIterFlag::ExternalLoop {
            // TODO: I don't want to make set fallible, but also we don't want to
            // support ExternalLoop yet (maybe ever?).
            panic!("rust-numpy does not currently support ExternalLoop access");
        }
        self.flags |= flag.to_c_enum();
        self
    }

    pub fn unset(mut self, flag: NpyIterFlag) -> Self {
        self.flags &= !flag.to_c_enum();
        self
    }

    pub fn build(self) -> PyResult<NpyIterSingleArray<'py, T>> {
        let iter_ptr = unsafe {
            PY_ARRAY_API.NpyIter_New(
                self.array.as_array_ptr(),
                self.flags,
                NPY_ORDER::NPY_ANYORDER,
                NPY_CASTING::NPY_SAFE_CASTING,
                ptr::null_mut(),
            )
        };
        let py = self.array.py();
        NpyIterSingleArray::new(iter_ptr, py).ok_or_else(|| PyErr::fetch(py))
    }
}

pub struct NpyIterSingleArray<'py, T> {
    iterator: ptr::NonNull<objects::NpyIter>,
    iternext: unsafe extern "C" fn(*mut objects::NpyIter) -> c_int,
    empty: bool,
    dataptr: *mut *mut c_char,

    return_type: PhantomData<T>,
    _py: Python<'py>,
}

impl<'py, T> NpyIterSingleArray<'py, T> {
    fn new(iterator: *mut objects::NpyIter, py: Python<'py>) -> Option<NpyIterSingleArray<'py, T>> {
        let mut iterator = ptr::NonNull::new(iterator)?;

        // TODO replace the null second arg with something correct.
        let iternext =
            unsafe { PY_ARRAY_API.NpyIter_GetIterNext(iterator.as_mut(), ptr::null_mut())? };
        let dataptr = unsafe { PY_ARRAY_API.NpyIter_GetDataPtrArray(iterator.as_mut()) };

        if dataptr.is_null() {
            unsafe { PY_ARRAY_API.NpyIter_Deallocate(iterator.as_mut()) };
        }

        Some(NpyIterSingleArray {
            iterator,
            iternext,
            empty: false, // TODO: Handle empty iterators
            dataptr,
            return_type: PhantomData,
            _py: py,
        })
    }
}

impl<'py, T> Drop for NpyIterSingleArray<'py, T> {
    fn drop(&mut self) {
        let _success = unsafe { PY_ARRAY_API.NpyIter_Deallocate(self.iterator.as_mut()) };
        // TODO: Handle _success somehow?
    }
}

impl<'py, T: 'py> std::iter::Iterator for NpyIterSingleArray<'py, T> {
    type Item = &'py T;

    fn next(&mut self) -> Option<Self::Item> {
        if self.empty {
            None
        } else {
            // Note: This pointer is correct and doesn't need to be updated,
            // note that we're derefencing a **char into a *char casting to a *T
            // and then transforming that into a reference, the value that dataptr
            // points to is being updated by iternext to point to the next value.
            let retval = Some(unsafe { &*(*self.dataptr as *mut T) });
            self.empty = unsafe { (self.iternext)(self.iterator.as_mut()) } == 0;
            retval
        }
    }
}

pub trait MultiIterMode {}

impl MultiIterMode for () {}

pub struct RO<S> {
    structure: PhantomData<S>,
}

impl<S: MultiIterMode> MultiIterMode for RO<S> {}

pub struct RW<S> {
    structure: PhantomData<S>,
}

impl<S: MultiIterMode> MultiIterMode for RW<S> {}

pub trait MultiIterModeHasManyArrays: MultiIterMode {}
impl MultiIterModeHasManyArrays for RO<RO<()>> {}
impl MultiIterModeHasManyArrays for RO<RW<()>> {}
impl MultiIterModeHasManyArrays for RW<RO<()>> {}
impl MultiIterModeHasManyArrays for RW<RW<()>> {}

impl<S: MultiIterModeHasManyArrays> MultiIterModeHasManyArrays for RO<S> {}
impl<S: MultiIterModeHasManyArrays> MultiIterModeHasManyArrays for RW<S> {}

pub struct NpyMultiIterBuilder<'py, T, S: MultiIterMode> {
    flags: npy_uint32,
    opflags: Vec<npy_uint32>,
    arrays: Vec<&'py PyArrayDyn<T>>,
    structure: PhantomData<S>,
}

impl<'py, T: TypeNum> NpyMultiIterBuilder<'py, T, ()> {
    pub fn new() -> Self {
        Self {
            flags: 0,
            opflags: Vec::new(),
            arrays: Vec::new(),
            structure: PhantomData,
        }
    }

    pub fn set(mut self, flag: NpyIterFlag) -> Self {
        if flag == NpyIterFlag::ExternalLoop {
            // TODO: I don't want to make set fallible, but also we don't want to
            // support ExternalLoop yet (maybe ever?).
            panic!("rust-numpy does not currently support ExternalLoop access");
        }
        self.flags |= flag.to_c_enum();
        self
    }

    pub fn unset(mut self, flag: NpyIterFlag) -> Self {
        self.flags &= !flag.to_c_enum();
        self
    }
}

impl<'py, T: TypeNum, S: MultiIterMode> NpyMultiIterBuilder<'py, T, S> {
    pub fn add_readonly_array<D: ndarray::Dimension>(
        mut self,
        array: &'py PyArray<T, D>,
    ) -> NpyMultiIterBuilder<'py, T, RO<S>> {
        self.arrays.push(array.into_dyn());
        self.opflags.push(NPY_ITER_READONLY);

        NpyMultiIterBuilder {
            flags: self.flags,
            opflags: self.opflags,
            arrays: self.arrays,
            structure: PhantomData,
        }
    }

    pub fn add_readwrite_array<D: ndarray::Dimension>(
        mut self,
        array: &'py PyArray<T, D>,
    ) -> NpyMultiIterBuilder<'py, T, RW<S>> {
        self.arrays.push(array.into_dyn());
        self.opflags.push(NPY_ITER_READWRITE);

        NpyMultiIterBuilder {
            flags: self.flags,
            opflags: self.opflags,
            arrays: self.arrays,
            structure: PhantomData,
        }
    }
}

impl<'py, T: TypeNum, S: MultiIterModeHasManyArrays> NpyMultiIterBuilder<'py, T, S> {
    pub fn build(mut self) -> PyResult<NpyMultiIterArray<'py, T, S>> {
        assert!(self.arrays.len() == self.opflags.len());
        assert!(self.arrays.len() <= i32::MAX as usize);
        assert!(2 <= self.arrays.len());

        let iter_ptr = unsafe {
            PY_ARRAY_API.NpyIter_MultiNew(
                self.arrays.len() as i32,
                self.arrays
                    .iter_mut()
                    .map(|x| x.as_array_ptr())
                    .collect::<Vec<_>>()
                    .as_mut_ptr(),
                self.flags,
                NPY_ORDER::NPY_ANYORDER,
                NPY_CASTING::NPY_SAFE_CASTING,
                self.opflags.as_mut_ptr(),
                ptr::null_mut(),
            )
        };
        let py = self.arrays[0].py();
        NpyMultiIterArray::new(iter_ptr, py).ok_or_else(|| PyErr::fetch(py))
    }
}

pub struct NpyMultiIterArray<'py, T, S: MultiIterModeHasManyArrays> {
    iterator: ptr::NonNull<objects::NpyIter>,
    iternext: unsafe extern "C" fn(*mut objects::NpyIter) -> c_int,
    empty: bool,
    dataptr: *mut *mut c_char,

    return_type: PhantomData<T>,
    structure: PhantomData<S>,
    _py: Python<'py>,
}

impl<'py, T, S: MultiIterModeHasManyArrays> NpyMultiIterArray<'py, T, S> {
    fn new(iterator: *mut objects::NpyIter, py: Python<'py>) -> Option<Self> {
        let mut iterator = ptr::NonNull::new(iterator)?;

        // TODO replace the null second arg with something correct.
        let iternext =
            unsafe { PY_ARRAY_API.NpyIter_GetIterNext(iterator.as_mut(), ptr::null_mut())? };
        let dataptr = unsafe { PY_ARRAY_API.NpyIter_GetDataPtrArray(iterator.as_mut()) };

        if dataptr.is_null() {
            unsafe { PY_ARRAY_API.NpyIter_Deallocate(iterator.as_mut()) };
        }

        Some(Self {
            iterator,
            iternext,
            empty: false, // TODO: Handle empty iterators
            dataptr,
            return_type: PhantomData,
            structure: PhantomData,
            _py: py,
        })
    }
}

impl<'py, T, S: MultiIterModeHasManyArrays> Drop for NpyMultiIterArray<'py, T, S> {
    fn drop(&mut self) {
        let _success = unsafe { PY_ARRAY_API.NpyIter_Deallocate(self.iterator.as_mut()) };
        // TODO: Handle _success somehow?
    }
}

impl<'py, T: 'py> std::iter::Iterator for NpyMultiIterArray<'py, T, RO<RO<()>>> {
    type Item = (&'py T, &'py T);

    fn next(&mut self) -> Option<Self::Item> {
        if self.empty {
            None
        } else {
            // Note: This pointer is correct and doesn't need to be updated,
            // note that we're derefencing a **char into a *char casting to a *T
            // and then transforming that into a reference, the value that dataptr
            // points to is being updated by iternext to point to the next value.
            let retval = Some(unsafe {
                (
                    &*(*self.dataptr as *mut T),
                    &*(*self.dataptr.offset(1) as *mut T),
                )
            });
            self.empty = unsafe { (self.iternext)(self.iterator.as_mut()) } == 0;
            retval
        }
    }
}

impl<'py, T: 'py> std::iter::Iterator for NpyMultiIterArray<'py, T, RO<RW<()>>> {
    type Item = (&'py mut T, &'py T);

    fn next(&mut self) -> Option<Self::Item> {
        if self.empty {
            None
        } else {
            // Note: This pointer is correct and doesn't need to be updated,
            // note that we're derefencing a **char into a *char casting to a *T
            // and then transforming that into a reference, the value that dataptr
            // points to is being updated by iternext to point to the next value.
            let retval = Some(unsafe {
                (
                    &mut *(*self.dataptr as *mut T),
                    &*(*self.dataptr.offset(1) as *mut T),
                )
            });
            self.empty = unsafe { (self.iternext)(self.iterator.as_mut()) } == 0;
            retval
        }
    }
}

impl<'py, T: 'py> std::iter::Iterator for NpyMultiIterArray<'py, T, RW<RO<()>>> {
    type Item = (&'py T, &'py mut T);

    fn next(&mut self) -> Option<Self::Item> {
        if self.empty {
            None
        } else {
            // Note: This pointer is correct and doesn't need to be updated,
            // note that we're derefencing a **char into a *char casting to a *T
            // and then transforming that into a reference, the value that dataptr
            // points to is being updated by iternext to point to the next value.
            let retval = Some(unsafe {
                (
                    &*(*self.dataptr as *mut T),
                    &mut *(*self.dataptr.offset(1) as *mut T),
                )
            });
            self.empty = unsafe { (self.iternext)(self.iterator.as_mut()) } == 0;
            retval
        }
    }
}

impl<'py, T: 'py> std::iter::Iterator for NpyMultiIterArray<'py, T, RW<RW<()>>> {
    type Item = (&'py mut T, &'py mut T);

    fn next(&mut self) -> Option<Self::Item> {
        if self.empty {
            None
        } else {
            // Note: This pointer is correct and doesn't need to be updated,
            // note that we're derefencing a **char into a *char casting to a *T
            // and then transforming that into a reference, the value that dataptr
            // points to is being updated by iternext to point to the next value.
            let retval = Some(unsafe {
                (
                    &mut *(*self.dataptr as *mut T),
                    &mut *(*self.dataptr.offset(1) as *mut T),
                )
            });
            self.empty = unsafe { (self.iternext)(self.iterator.as_mut()) } == 0;
            retval
        }
    }
}
<commit_msg>Switches to macros to generate the impls for Iterator on MultiIter<commit_after>use crate::array::{PyArray, PyArrayDyn};
use crate::npyffi::{
    array::PY_ARRAY_API,
    types::{NPY_CASTING, NPY_ORDER},
    *,
};
use crate::types::TypeNum;
use pyo3::{prelude::*, PyNativeType};

use std::marker::PhantomData;
use std::os::raw::*;
use std::ptr;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum NpyIterFlag {
    CIndex,
    FIndex,
    MultiIndex,
    ExternalLoop,
    CommonDtype,
    RefsOk,
    ZerosizeOk,
    ReduceOk,
    Ranged,
    Buffered,
    GrowInner,
    DelayBufAlloc,
    DontNegateStrides,
    CopyIfOverlap,
    ReadWrite,
    ReadOnly,
    WriteOnly,
}

impl NpyIterFlag {
    fn to_c_enum(&self) -> npy_uint32 {
        use NpyIterFlag::*;
        match self {
            CIndex => NPY_ITER_C_INDEX,
            FIndex => NPY_ITER_C_INDEX,
            MultiIndex => NPY_ITER_MULTI_INDEX,
            ExternalLoop => NPY_ITER_EXTERNAL_LOOP,
            CommonDtype => NPY_ITER_COMMON_DTYPE,
            RefsOk => NPY_ITER_REFS_OK,
            ZerosizeOk => NPY_ITER_ZEROSIZE_OK,
            ReduceOk => NPY_ITER_REDUCE_OK,
            Ranged => NPY_ITER_RANGED,
            Buffered => NPY_ITER_BUFFERED,
            GrowInner => NPY_ITER_GROWINNER,
            DelayBufAlloc => NPY_ITER_DELAY_BUFALLOC,
            DontNegateStrides => NPY_ITER_DONT_NEGATE_STRIDES,
            CopyIfOverlap => NPY_ITER_COPY_IF_OVERLAP,
            ReadWrite => NPY_ITER_READWRITE,
            ReadOnly => NPY_ITER_READONLY,
            WriteOnly => NPY_ITER_WRITEONLY,
        }
    }
}

pub struct NpyIterBuilder<'py, T> {
    flags: npy_uint32,
    array: &'py PyArrayDyn<T>,
}

impl<'py, T: TypeNum> NpyIterBuilder<'py, T> {
    pub fn new<D: ndarray::Dimension>(array: &'py PyArray<T, D>) -> NpyIterBuilder<'py, T> {
        NpyIterBuilder {
            flags: 0,
            array: array.into_dyn(),
        }
    }

    pub fn set(mut self, flag: NpyIterFlag) -> Self {
        if flag == NpyIterFlag::ExternalLoop {
            // TODO: I don't want to make set fallible, but also we don't want to
            // support ExternalLoop yet (maybe ever?).
            panic!("rust-numpy does not currently support ExternalLoop access");
        }
        self.flags |= flag.to_c_enum();
        self
    }

    pub fn unset(mut self, flag: NpyIterFlag) -> Self {
        self.flags &= !flag.to_c_enum();
        self
    }

    pub fn build(self) -> PyResult<NpyIterSingleArray<'py, T>> {
        let iter_ptr = unsafe {
            PY_ARRAY_API.NpyIter_New(
                self.array.as_array_ptr(),
                self.flags,
                NPY_ORDER::NPY_ANYORDER,
                NPY_CASTING::NPY_SAFE_CASTING,
                ptr::null_mut(),
            )
        };
        let py = self.array.py();
        NpyIterSingleArray::new(iter_ptr, py).ok_or_else(|| PyErr::fetch(py))
    }
}

pub struct NpyIterSingleArray<'py, T> {
    iterator: ptr::NonNull<objects::NpyIter>,
    iternext: unsafe extern "C" fn(*mut objects::NpyIter) -> c_int,
    empty: bool,
    dataptr: *mut *mut c_char,

    return_type: PhantomData<T>,
    _py: Python<'py>,
}

impl<'py, T> NpyIterSingleArray<'py, T> {
    fn new(iterator: *mut objects::NpyIter, py: Python<'py>) -> Option<NpyIterSingleArray<'py, T>> {
        let mut iterator = ptr::NonNull::new(iterator)?;

        // TODO replace the null second arg with something correct.
        let iternext =
            unsafe { PY_ARRAY_API.NpyIter_GetIterNext(iterator.as_mut(), ptr::null_mut())? };
        let dataptr = unsafe { PY_ARRAY_API.NpyIter_GetDataPtrArray(iterator.as_mut()) };

        if dataptr.is_null() {
            unsafe { PY_ARRAY_API.NpyIter_Deallocate(iterator.as_mut()) };
        }

        Some(NpyIterSingleArray {
            iterator,
            iternext,
            empty: false, // TODO: Handle empty iterators
            dataptr,
            return_type: PhantomData,
            _py: py,
        })
    }
}

impl<'py, T> Drop for NpyIterSingleArray<'py, T> {
    fn drop(&mut self) {
        let _success = unsafe { PY_ARRAY_API.NpyIter_Deallocate(self.iterator.as_mut()) };
        // TODO: Handle _success somehow?
    }
}

impl<'py, T: 'py> std::iter::Iterator for NpyIterSingleArray<'py, T> {
    type Item = &'py T;

    fn next(&mut self) -> Option<Self::Item> {
        if self.empty {
            None
        } else {
            // Note: This pointer is correct and doesn't need to be updated,
            // note that we're derefencing a **char into a *char casting to a *T
            // and then transforming that into a reference, the value that dataptr
            // points to is being updated by iternext to point to the next value.
            let retval = Some(unsafe { &*(*self.dataptr as *mut T) });
            self.empty = unsafe { (self.iternext)(self.iterator.as_mut()) } == 0;
            retval
        }
    }
}

pub trait MultiIterMode {}

impl MultiIterMode for () {}

pub struct RO<S: MultiIterMode> {
    structure: PhantomData<S>,
}

impl<S: MultiIterMode> MultiIterMode for RO<S> {}

pub struct RW<S: MultiIterMode> {
    structure: PhantomData<S>,
}

impl<S: MultiIterMode> MultiIterMode for RW<S> {}

pub trait MultiIterModeHasManyArrays: MultiIterMode {}
impl MultiIterModeHasManyArrays for RO<RO<()>> {}
impl MultiIterModeHasManyArrays for RO<RW<()>> {}
impl MultiIterModeHasManyArrays for RW<RO<()>> {}
impl MultiIterModeHasManyArrays for RW<RW<()>> {}

impl<S: MultiIterModeHasManyArrays> MultiIterModeHasManyArrays for RO<S> {}
impl<S: MultiIterModeHasManyArrays> MultiIterModeHasManyArrays for RW<S> {}

pub struct NpyMultiIterBuilder<'py, T, S: MultiIterMode> {
    flags: npy_uint32,
    opflags: Vec<npy_uint32>,
    arrays: Vec<&'py PyArrayDyn<T>>,
    structure: PhantomData<S>,
}

impl<'py, T: TypeNum> NpyMultiIterBuilder<'py, T, ()> {
    pub fn new() -> Self {
        Self {
            flags: 0,
            opflags: Vec::new(),
            arrays: Vec::new(),
            structure: PhantomData,
        }
    }

    pub fn set(mut self, flag: NpyIterFlag) -> Self {
        if flag == NpyIterFlag::ExternalLoop {
            // TODO: I don't want to make set fallible, but also we don't want to
            // support ExternalLoop yet (maybe ever?).
            panic!("rust-numpy does not currently support ExternalLoop access");
        }
        self.flags |= flag.to_c_enum();
        self
    }

    pub fn unset(mut self, flag: NpyIterFlag) -> Self {
        self.flags &= !flag.to_c_enum();
        self
    }
}

impl<'py, T: TypeNum, S: MultiIterMode> NpyMultiIterBuilder<'py, T, S> {
    pub fn add_readonly_array<D: ndarray::Dimension>(
        mut self,
        array: &'py PyArray<T, D>,
    ) -> NpyMultiIterBuilder<'py, T, RO<S>> {
        self.arrays.push(array.into_dyn());
        self.opflags.push(NPY_ITER_READONLY);

        NpyMultiIterBuilder {
            flags: self.flags,
            opflags: self.opflags,
            arrays: self.arrays,
            structure: PhantomData,
        }
    }

    pub fn add_readwrite_array<D: ndarray::Dimension>(
        mut self,
        array: &'py PyArray<T, D>,
    ) -> NpyMultiIterBuilder<'py, T, RW<S>> {
        self.arrays.push(array.into_dyn());
        self.opflags.push(NPY_ITER_READWRITE);

        NpyMultiIterBuilder {
            flags: self.flags,
            opflags: self.opflags,
            arrays: self.arrays,
            structure: PhantomData,
        }
    }
}

impl<'py, T: TypeNum, S: MultiIterModeHasManyArrays> NpyMultiIterBuilder<'py, T, S> {
    pub fn build(mut self) -> PyResult<NpyMultiIterArray<'py, T, S>> {
        assert!(self.arrays.len() == self.opflags.len());
        assert!(self.arrays.len() <= i32::MAX as usize);
        assert!(2 <= self.arrays.len());

        let iter_ptr = unsafe {
            PY_ARRAY_API.NpyIter_MultiNew(
                self.arrays.len() as i32,
                self.arrays
                    .iter_mut()
                    .map(|x| x.as_array_ptr())
                    .collect::<Vec<_>>()
                    .as_mut_ptr(),
                self.flags,
                NPY_ORDER::NPY_ANYORDER,
                NPY_CASTING::NPY_SAFE_CASTING,
                self.opflags.as_mut_ptr(),
                ptr::null_mut(),
            )
        };
        let py = self.arrays[0].py();
        NpyMultiIterArray::new(iter_ptr, py).ok_or_else(|| PyErr::fetch(py))
    }
}

pub struct NpyMultiIterArray<'py, T, S: MultiIterModeHasManyArrays> {
    iterator: ptr::NonNull<objects::NpyIter>,
    iternext: unsafe extern "C" fn(*mut objects::NpyIter) -> c_int,
    empty: bool,
    dataptr: *mut *mut c_char,

    return_type: PhantomData<T>,
    structure: PhantomData<S>,
    _py: Python<'py>,
}

impl<'py, T, S: MultiIterModeHasManyArrays> NpyMultiIterArray<'py, T, S> {
    fn new(iterator: *mut objects::NpyIter, py: Python<'py>) -> Option<Self> {
        let mut iterator = ptr::NonNull::new(iterator)?;

        // TODO replace the null second arg with something correct.
        let iternext =
            unsafe { PY_ARRAY_API.NpyIter_GetIterNext(iterator.as_mut(), ptr::null_mut())? };
        let dataptr = unsafe { PY_ARRAY_API.NpyIter_GetDataPtrArray(iterator.as_mut()) };

        if dataptr.is_null() {
            unsafe { PY_ARRAY_API.NpyIter_Deallocate(iterator.as_mut()) };
        }

        Some(Self {
            iterator,
            iternext,
            empty: false, // TODO: Handle empty iterators
            dataptr,
            return_type: PhantomData,
            structure: PhantomData,
            _py: py,
        })
    }
}

impl<'py, T, S: MultiIterModeHasManyArrays> Drop for NpyMultiIterArray<'py, T, S> {
    fn drop(&mut self) {
        let _success = unsafe { PY_ARRAY_API.NpyIter_Deallocate(self.iterator.as_mut()) };
        // TODO: Handle _success somehow?
    }
}

macro_rules! implement_iter_on_type {
    ( $arg:ty, $ty:ty, $arg_name:ident, $sol:expr ) =>
    {
impl<'py, T: 'py> std::iter::Iterator for NpyMultiIterArray<'py, T, $arg> {
    type Item = $ty;

    fn next(&mut $arg_name) -> Option<Self::Item> {
        if $arg_name.empty {
            None
        } else {
            // Note: This pointer is correct and doesn't need to be updated,
            // note that we're derefencing a **char into a *char casting to a *T
            // and then transforming that into a reference, the value that dataptr
            // points to is being updated by iternext to point to the next value.
            let retval = Some(unsafe {
                    $sol
            });
            $arg_name.empty = unsafe { ($arg_name.iternext)($arg_name.iterator.as_mut()) } == 0;
            retval
        }
    }
}
    }
}

implement_iter_on_type!(
    RO<RO<()>>,
    (&'py T, &'py T),
    self,
    (
        &*(*self.dataptr as *mut T),
        &*(*self.dataptr.offset(1) as *mut T),
    )
);

implement_iter_on_type!(
    RO<RW<()>>,
    (&'py mut T, &'py T),
    self,
    (
        &mut *(*self.dataptr as *mut T),
        &*(*self.dataptr.offset(1) as *mut T),
    )
);

implement_iter_on_type!(
    RW<RO<()>>,
    (&'py T, &'py mut T),
    self,
    (
        &*(*self.dataptr as *mut T),
        &mut *(*self.dataptr.offset(1) as *mut T),
    )
);

implement_iter_on_type!(
    RW<RW<()>>,
    (&'py mut T, &'py mut T),
    self,
    (
        &mut *(*self.dataptr as *mut T),
        &mut *(*self.dataptr.offset(1) as *mut T),
    )
);

implement_iter_on_type!(
    RW<RW<RW<()>>>,
    (&'py mut T, &'py mut T, &'py mut T),
    self,
    (
        &mut *(*self.dataptr as *mut T),
        &mut *(*self.dataptr.offset(1) as *mut T),
        &mut *(*self.dataptr.offset(2) as *mut T),
    )
);

implement_iter_on_type!(
    RW<RW<RO<()>>>,
    (&'py T, &'py mut T, &'py mut T),
    self,
    (
        &*(*self.dataptr as *mut T),
        &mut *(*self.dataptr.offset(1) as *mut T),
        &mut *(*self.dataptr.offset(2) as *mut T),
    )
);

implement_iter_on_type!(
    RW<RO<RW<()>>>,
    (&'py mut T, &'py T, &'py mut T),
    self,
    (
        &mut *(*self.dataptr as *mut T),
        &*(*self.dataptr.offset(1) as *mut T),
        &mut *(*self.dataptr.offset(2) as *mut T),
    )
);

implement_iter_on_type!(
    RO<RW<RW<()>>>,
    (&'py mut T, &'py mut T, &'py T),
    self,
    (
        &mut *(*self.dataptr as *mut T),
        &mut *(*self.dataptr.offset(1) as *mut T),
        &*(*self.dataptr.offset(2) as *mut T),
    )
);

implement_iter_on_type!(
    RW<RO<RO<()>>>,
    (&'py T, &'py T, &'py mut T),
    self,
    (
        &*(*self.dataptr as *mut T),
        &*(*self.dataptr.offset(1) as *mut T),
        &mut *(*self.dataptr.offset(2) as *mut T),
    )
);

implement_iter_on_type!(
    RO<RW<RO<()>>>,
    (&'py T, &'py mut T, &'py T),
    self,
    (
        &*(*self.dataptr as *mut T),
        &mut *(*self.dataptr.offset(1) as *mut T),
        &*(*self.dataptr.offset(2) as *mut T),
    )
);

implement_iter_on_type!(
    RO<RO<RW<()>>>,
    (&'py mut T, &'py T, &'py T),
    self,
    (
        &mut *(*self.dataptr as *mut T),
        &*(*self.dataptr.offset(1) as *mut T),
        &*(*self.dataptr.offset(2) as *mut T),
    )
);

implement_iter_on_type!(
    RO<RO<RO<()>>>,
    (&'py T, &'py T, &'py T),
    self,
    (
        &*(*self.dataptr as *mut T),
        &*(*self.dataptr.offset(1) as *mut T),
        &*(*self.dataptr.offset(2) as *mut T),
    )
);
<|endoftext|>


<commit_before>mod rustnsobject;

extern crate objc;
extern crate objc_foundation;
extern crate cocoa;

extern crate fruitbasket;
use self::fruitbasket::FruitApp;

pub use ::TStatusBar;
pub use ::NSCallback;

use objc::runtime::Class;

use self::cocoa::base::{nil, YES};
use self::cocoa::appkit::NSStatusBar;
use self::cocoa::foundation::NSString;
use self::cocoa::appkit::{NSMenu,
                          NSMenuItem,
                          NSImage,
                          NSVariableStatusItemLength,
                          NSStatusItem,
                          NSButton};

use self::rustnsobject::{NSObj, NSObjTrait, NSObjCallbackTrait};

use std::sync::mpsc::Sender;
use std::ptr;
use std::ffi::CStr;

pub type Object = objc::runtime::Object;

pub struct OSXStatusBar {
    object: NSObj,
    app: FruitApp,
    status_bar_item: *mut objc::runtime::Object,
    menu_bar: *mut objc::runtime::Object,
}

impl TStatusBar for OSXStatusBar {
    type S = OSXStatusBar;
    fn new(tx: Sender<String>) -> OSXStatusBar {
        let mut bar;
        unsafe {
            let nsapp = FruitApp::new();
            nsapp.set_activation_policy(fruitbasket::ActivationPolicy::Prohibited);
            let status_bar = NSStatusBar::systemStatusBar(nil);
            bar = OSXStatusBar {
                app: nsapp,
                status_bar_item: status_bar.statusItemWithLength_(NSVariableStatusItemLength),
                menu_bar: NSMenu::new(nil),
                object: NSObj::alloc(tx),
            };

            // Default mode for menu bar items: blue highlight when selected
            let _: () = msg_send![bar.status_bar_item, setHighlightMode:YES];

            // Set title.  Only displayed if image fails to load.
            let title = NSString::alloc(nil).init_str("connectr");
            NSButton::setTitle_(bar.status_bar_item, title);
            let _: () = msg_send![title, release];

            // Look for icon in OS X bundle if there is one, otherwise current dir.
            // See docs/icons.md for explanation of icon files.
            // TODO: Use the full list of search paths.
            let icon_name = "connectr_80px_300dpi";
            let img_path = match fruitbasket::FruitApp::bundled_resource_path(icon_name, "png") {
                Some(path) => path,
                None => format!("{}.png", icon_name),
            };

            // Set the status bar image.  Switching on setTemplate switches it to
            // using OS X system-style icons that are masked to all white.  I
            // prefer color, but that should maybe be configurable.
            let img = NSString::alloc(nil).init_str(&img_path);
            let icon = NSImage::alloc(nil).initWithContentsOfFile_(img);
            #[cfg(feature = "mac_white_icon")]
            let _: () = msg_send![icon, setTemplate: YES]; // enable to make icon white
            bar.status_bar_item.button().setImage_(icon);
            let _: () = msg_send![img, release];
            let _: () = msg_send![icon, release];

            // Add the same image again as an alternate image.  I'm not sure how the
            // blending is performed, but it behaves differently and better if an
            // alt image is specified.  Without an alt image, the icon darkens too
            // much in 'dark mode' when selected, and is too light in 'light mode'.
            let img = NSString::alloc(nil).init_str(&img_path);
            let icon = NSImage::alloc(nil).initWithContentsOfFile_(img);
            let _: () = msg_send![bar.status_bar_item.button(), setAlternateImage: icon];
            let _: () = msg_send![img, release];
            let _: () = msg_send![icon, release];

            bar.status_bar_item.setMenu_(bar.menu_bar);
            bar.object.cb_fn = Some(Box::new(
                move |s, sender| {
                    let cb = s.get_value(sender);
                    cb(sender, &s.tx);
                }
            ));
        }
        bar
    }
    fn can_redraw(&mut self) -> bool {
        true
    }
    fn clear_items(&mut self) {
        unsafe {
            let old_menu = self.menu_bar;
            self.menu_bar = NSMenu::new(nil);
            self.status_bar_item.setMenu_(self.menu_bar);
            let _: () = msg_send![old_menu, removeAllItems];
            let _: () = msg_send![old_menu, release];
        }
    }
    fn set_tooltip(&mut self, text: &str) {
        unsafe {
            let img = NSString::alloc(nil).init_str(text);
            let _: () = msg_send![self.status_bar_item.button(), setToolTip: img];
            let _: () = msg_send![img, release];
        }
    }
    fn add_label(&mut self, label: &str) {
        unsafe {
            let txt = NSString::alloc(nil).init_str(label);
            let quit_key = NSString::alloc(nil).init_str("");
            let app_menu_item = NSMenuItem::alloc(nil)
                .initWithTitle_action_keyEquivalent_(txt, self.object.selector(), quit_key);
            let _: () = msg_send![txt, release];
            let _: () = msg_send![quit_key, release];
            self.menu_bar.addItem_(app_menu_item);
            let _: () = msg_send![app_menu_item, release];
        }
    }
    fn add_quit(&mut self, label: &str) {
        unsafe {
            let txt = NSString::alloc(nil).init_str(label);
            let quit_key = NSString::alloc(nil).init_str("");
            let app_menu_item = NSMenuItem::alloc(nil)
                .initWithTitle_action_keyEquivalent_(txt, sel!(terminate:), quit_key);
            let _: () = msg_send![txt, release];
            let _: () = msg_send![quit_key, release];
            self.menu_bar.addItem_(app_menu_item);
            let _: () = msg_send![app_menu_item, release];
        }
    }
    fn add_separator(&mut self) {
        unsafe {
            let cls = Class::get("NSMenuItem").unwrap();
            let sep: *mut Object = msg_send![cls, separatorItem];
            self.menu_bar.addItem_(sep);
        }
    }
    // TODO: whole API should accept menu option.  this whole thing should
    // be split out into its own recursive menu-builder trait.  this is
    // horrible.
    fn add_item(&mut self, menu: Option<*mut Object>,item: &str, callback: NSCallback, selected: bool) -> *mut Object {
        unsafe {
            let txt = NSString::alloc(nil).init_str(item);
            let quit_key = NSString::alloc(nil).init_str("");
            let app_menu_item = NSMenuItem::alloc(nil)
                .initWithTitle_action_keyEquivalent_(txt, self.object.selector(), quit_key);
            let _: () = msg_send![txt, release];
            let _: () = msg_send![quit_key, release];
            self.object.add_callback(app_menu_item, callback);
            let objc = self.object.take_objc();
            let _: () = msg_send![app_menu_item, setTarget: objc];
            if selected {
                let _: () = msg_send![app_menu_item, setState: 1];
            }
            let item: *mut Object = app_menu_item;
            match menu {
                Some(menu) => { menu.addItem_(app_menu_item); },
                None => { self.menu_bar.addItem_(app_menu_item); }
            }
            let _: () = msg_send![app_menu_item, release];
            item
        }
    }
    fn add_submenu(&mut self, label: &str, callback: NSCallback) -> *mut Object {
        unsafe {
            let submenu = NSMenu::new(nil);
            let txt = NSString::alloc(nil).init_str(label);
            let quit_key = NSString::alloc(nil).init_str("");
            let app_menu_item = NSMenuItem::alloc(nil)
                .initWithTitle_action_keyEquivalent_(txt,
                                                     self.object.selector(),
                                                     quit_key);
            self.object.add_callback(app_menu_item, callback);
            let objc = self.object.take_objc();
            let _: () = msg_send![app_menu_item, setTarget: objc];
            let _ = msg_send![app_menu_item, setSubmenu: submenu];
            let _ = msg_send![txt, release];
            let _ = msg_send![quit_key, release];
            self.menu_bar.addItem_(app_menu_item);
            let _ = msg_send![app_menu_item, release];
            submenu
        }
    }
    fn update_item(&mut self, item: *mut Object, label: &str) {
        unsafe {
            let ns_label = NSString::alloc(nil).init_str(label);
            let _: () = msg_send![item, setTitle: ns_label];
            let _: () = msg_send![ns_label, release];
        }
    }
    fn sel_item(&mut self, sender: u64) {
        let target: *mut Object = sender as *mut Object;
        unsafe {
            let _: () = msg_send![target, setState: 1];
        }
    }
    fn unsel_item(&mut self, sender: u64) {
        let target: *mut Object = sender as *mut Object;
        unsafe {
            let _: () = msg_send![target, setState: 0];
        }
    }
    fn run(&mut self, block: bool) {
        let period = match block {
            true => fruitbasket::RunPeriod::Forever,
            _ => fruitbasket::RunPeriod::Once,
        };
        let _ = self.app.run(period);
    }
}

//pub fn osx_alert(text: &str) {
//    unsafe {
//        let ns_text = NSString::alloc(nil).init_str(text);
//        let button = NSString::alloc(nil).init_str("ok");
//        let cls = Class::get("NSAlert").unwrap();
//        let alert: *mut Object = msg_send![cls, alloc];
//        let _: () = msg_send![alert, init];
//        let _: () = msg_send![alert, setMessageText: ns_text];
//        let _: () = msg_send![alert, addButtonWithTitle: button];
//        let _: () = msg_send![alert, runModal];
//        let _: () = msg_send![ns_text, release];
//        let _: () = msg_send![button, release];
//        let _: () = msg_send![alert, release];
//    }
//}

pub fn resource_dir() -> Option<String> {
    unsafe {
        let cls = Class::get("NSBundle").unwrap();
        let bundle: *mut Object = msg_send![cls, mainBundle];
        let path: *mut Object = msg_send![bundle, resourcePath];
        let cstr: *const i8 = msg_send![path, UTF8String];
        if cstr != ptr::null() {
            let rstr = CStr::from_ptr(cstr).to_string_lossy().into_owned();
            return Some(rstr);
        }
        None
    }
}
<commit_msg>Fix msg_send return types on submenu changes<commit_after>mod rustnsobject;

extern crate objc;
extern crate objc_foundation;
extern crate cocoa;

extern crate fruitbasket;
use self::fruitbasket::FruitApp;

pub use ::TStatusBar;
pub use ::NSCallback;

use objc::runtime::Class;

use self::cocoa::base::{nil, YES};
use self::cocoa::appkit::NSStatusBar;
use self::cocoa::foundation::NSString;
use self::cocoa::appkit::{NSMenu,
                          NSMenuItem,
                          NSImage,
                          NSVariableStatusItemLength,
                          NSStatusItem,
                          NSButton};

use self::rustnsobject::{NSObj, NSObjTrait, NSObjCallbackTrait};

use std::sync::mpsc::Sender;
use std::ptr;
use std::ffi::CStr;

pub type Object = objc::runtime::Object;

pub struct OSXStatusBar {
    object: NSObj,
    app: FruitApp,
    status_bar_item: *mut objc::runtime::Object,
    menu_bar: *mut objc::runtime::Object,
}

impl TStatusBar for OSXStatusBar {
    type S = OSXStatusBar;
    fn new(tx: Sender<String>) -> OSXStatusBar {
        let mut bar;
        unsafe {
            let nsapp = FruitApp::new();
            nsapp.set_activation_policy(fruitbasket::ActivationPolicy::Prohibited);
            let status_bar = NSStatusBar::systemStatusBar(nil);
            bar = OSXStatusBar {
                app: nsapp,
                status_bar_item: status_bar.statusItemWithLength_(NSVariableStatusItemLength),
                menu_bar: NSMenu::new(nil),
                object: NSObj::alloc(tx),
            };

            // Default mode for menu bar items: blue highlight when selected
            let _: () = msg_send![bar.status_bar_item, setHighlightMode:YES];

            // Set title.  Only displayed if image fails to load.
            let title = NSString::alloc(nil).init_str("connectr");
            NSButton::setTitle_(bar.status_bar_item, title);
            let _: () = msg_send![title, release];

            // Look for icon in OS X bundle if there is one, otherwise current dir.
            // See docs/icons.md for explanation of icon files.
            // TODO: Use the full list of search paths.
            let icon_name = "connectr_80px_300dpi";
            let img_path = match fruitbasket::FruitApp::bundled_resource_path(icon_name, "png") {
                Some(path) => path,
                None => format!("{}.png", icon_name),
            };

            // Set the status bar image.  Switching on setTemplate switches it to
            // using OS X system-style icons that are masked to all white.  I
            // prefer color, but that should maybe be configurable.
            let img = NSString::alloc(nil).init_str(&img_path);
            let icon = NSImage::alloc(nil).initWithContentsOfFile_(img);
            #[cfg(feature = "mac_white_icon")]
            let _: () = msg_send![icon, setTemplate: YES]; // enable to make icon white
            bar.status_bar_item.button().setImage_(icon);
            let _: () = msg_send![img, release];
            let _: () = msg_send![icon, release];

            // Add the same image again as an alternate image.  I'm not sure how the
            // blending is performed, but it behaves differently and better if an
            // alt image is specified.  Without an alt image, the icon darkens too
            // much in 'dark mode' when selected, and is too light in 'light mode'.
            let img = NSString::alloc(nil).init_str(&img_path);
            let icon = NSImage::alloc(nil).initWithContentsOfFile_(img);
            let _: () = msg_send![bar.status_bar_item.button(), setAlternateImage: icon];
            let _: () = msg_send![img, release];
            let _: () = msg_send![icon, release];

            bar.status_bar_item.setMenu_(bar.menu_bar);
            bar.object.cb_fn = Some(Box::new(
                move |s, sender| {
                    let cb = s.get_value(sender);
                    cb(sender, &s.tx);
                }
            ));
        }
        bar
    }
    fn can_redraw(&mut self) -> bool {
        true
    }
    fn clear_items(&mut self) {
        unsafe {
            let old_menu = self.menu_bar;
            self.menu_bar = NSMenu::new(nil);
            self.status_bar_item.setMenu_(self.menu_bar);
            let _: () = msg_send![old_menu, removeAllItems];
            let _: () = msg_send![old_menu, release];
        }
    }
    fn set_tooltip(&mut self, text: &str) {
        unsafe {
            let img = NSString::alloc(nil).init_str(text);
            let _: () = msg_send![self.status_bar_item.button(), setToolTip: img];
            let _: () = msg_send![img, release];
        }
    }
    fn add_label(&mut self, label: &str) {
        unsafe {
            let txt = NSString::alloc(nil).init_str(label);
            let quit_key = NSString::alloc(nil).init_str("");
            let app_menu_item = NSMenuItem::alloc(nil)
                .initWithTitle_action_keyEquivalent_(txt, self.object.selector(), quit_key);
            let _: () = msg_send![txt, release];
            let _: () = msg_send![quit_key, release];
            self.menu_bar.addItem_(app_menu_item);
            let _: () = msg_send![app_menu_item, release];
        }
    }
    fn add_quit(&mut self, label: &str) {
        unsafe {
            let txt = NSString::alloc(nil).init_str(label);
            let quit_key = NSString::alloc(nil).init_str("");
            let app_menu_item = NSMenuItem::alloc(nil)
                .initWithTitle_action_keyEquivalent_(txt, sel!(terminate:), quit_key);
            let _: () = msg_send![txt, release];
            let _: () = msg_send![quit_key, release];
            self.menu_bar.addItem_(app_menu_item);
            let _: () = msg_send![app_menu_item, release];
        }
    }
    fn add_separator(&mut self) {
        unsafe {
            let cls = Class::get("NSMenuItem").unwrap();
            let sep: *mut Object = msg_send![cls, separatorItem];
            self.menu_bar.addItem_(sep);
        }
    }
    // TODO: whole API should accept menu option.  this whole thing should
    // be split out into its own recursive menu-builder trait.  this is
    // horrible.
    fn add_item(&mut self, menu: Option<*mut Object>,item: &str, callback: NSCallback, selected: bool) -> *mut Object {
        unsafe {
            let txt = NSString::alloc(nil).init_str(item);
            let quit_key = NSString::alloc(nil).init_str("");
            let app_menu_item = NSMenuItem::alloc(nil)
                .initWithTitle_action_keyEquivalent_(txt, self.object.selector(), quit_key);
            let _: () = msg_send![txt, release];
            let _: () = msg_send![quit_key, release];
            self.object.add_callback(app_menu_item, callback);
            let objc = self.object.take_objc();
            let _: () = msg_send![app_menu_item, setTarget: objc];
            if selected {
                let _: () = msg_send![app_menu_item, setState: 1];
            }
            let item: *mut Object = app_menu_item;
            match menu {
                Some(menu) => { menu.addItem_(app_menu_item); },
                None => { self.menu_bar.addItem_(app_menu_item); }
            }
            let _: () = msg_send![app_menu_item, release];
            item
        }
    }
    fn add_submenu(&mut self, label: &str, callback: NSCallback) -> *mut Object {
        unsafe {
            let submenu = NSMenu::new(nil);
            let txt = NSString::alloc(nil).init_str(label);
            let quit_key = NSString::alloc(nil).init_str("");
            let app_menu_item = NSMenuItem::alloc(nil)
                .initWithTitle_action_keyEquivalent_(txt,
                                                     self.object.selector(),
                                                     quit_key);
            self.object.add_callback(app_menu_item, callback);
            let objc = self.object.take_objc();
            let _: () = msg_send![app_menu_item, setTarget: objc];
            let _: () = msg_send![app_menu_item, setSubmenu: submenu];
            let _: () = msg_send![txt, release];
            let _: () = msg_send![quit_key, release];
            self.menu_bar.addItem_(app_menu_item);
            let _: () = msg_send![app_menu_item, release];
            submenu
        }
    }
    fn update_item(&mut self, item: *mut Object, label: &str) {
        unsafe {
            let ns_label = NSString::alloc(nil).init_str(label);
            let _: () = msg_send![item, setTitle: ns_label];
            let _: () = msg_send![ns_label, release];
        }
    }
    fn sel_item(&mut self, sender: u64) {
        let target: *mut Object = sender as *mut Object;
        unsafe {
            let _: () = msg_send![target, setState: 1];
        }
    }
    fn unsel_item(&mut self, sender: u64) {
        let target: *mut Object = sender as *mut Object;
        unsafe {
            let _: () = msg_send![target, setState: 0];
        }
    }
    fn run(&mut self, block: bool) {
        let period = match block {
            true => fruitbasket::RunPeriod::Forever,
            _ => fruitbasket::RunPeriod::Once,
        };
        let _ = self.app.run(period);
    }
}

//pub fn osx_alert(text: &str) {
//    unsafe {
//        let ns_text = NSString::alloc(nil).init_str(text);
//        let button = NSString::alloc(nil).init_str("ok");
//        let cls = Class::get("NSAlert").unwrap();
//        let alert: *mut Object = msg_send![cls, alloc];
//        let _: () = msg_send![alert, init];
//        let _: () = msg_send![alert, setMessageText: ns_text];
//        let _: () = msg_send![alert, addButtonWithTitle: button];
//        let _: () = msg_send![alert, runModal];
//        let _: () = msg_send![ns_text, release];
//        let _: () = msg_send![button, release];
//        let _: () = msg_send![alert, release];
//    }
//}

pub fn resource_dir() -> Option<String> {
    unsafe {
        let cls = Class::get("NSBundle").unwrap();
        let bundle: *mut Object = msg_send![cls, mainBundle];
        let path: *mut Object = msg_send![bundle, resourcePath];
        let cstr: *const i8 = msg_send![path, UTF8String];
        if cstr != ptr::null() {
            let rstr = CStr::from_ptr(cstr).to_string_lossy().into_owned();
            return Some(rstr);
        }
        None
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate neon;

use neon::vm::{ Call, JsResult };
use neon::js::{ JsString, Variant };

fn hello(call: Call) -> JsResult<JsString> {
    let scope = call.scope;
    Ok(JsString::new(scope, "hello node").unwrap())
}

fn hello2(call: Call) -> JsResult<JsString> {
    let mut scope = call.scope;
    let arguments = call.arguments;
    let int_value = try!(arguments.require(scope, 0));

    match int_value.variant() {
        Variant::Number(v) => { println!("number: {:?}", v.value()) },
        Variant::Integer(v) => { println!("integer: {:?}", v.value()); },
        _ => { println!("oops!"); }
    }
    Ok(JsString::new(scope, "hello node").unwrap())
}

register_module!(m, {
//    m.export("hello", hello),
    m.export("hello2", hello2)
});
<commit_msg>fix module export<commit_after>#[macro_use]
extern crate neon;

use neon::vm::{ Call, JsResult };
use neon::js::{ JsString, Variant };

fn hello(call: Call) -> JsResult<JsString> {
    let scope = call.scope;
    Ok(JsString::new(scope, "hello node").unwrap())
}

fn hello2(call: Call) -> JsResult<JsString> {
    let mut scope = call.scope;
    let arguments = call.arguments;
    let int_value = try!(arguments.require(scope, 0));

    match int_value.variant() {
        Variant::Number(v) => { println!("number: {:?}", v.value()) },
        Variant::Integer(v) => { println!("integer: {:?}", v.value()); },
        _ => { println!("oops!"); }
    }
    Ok(JsString::new(scope, "hello node").unwrap())
}

register_module!(m, {
    try!(m.export("hello", hello));
    try!(m.export("hello2", hello2));
    Ok(())
});
<|endoftext|>


<commit_before>//! Makes drawing on ncurses windows easier.

use backend::Backend;
use enumset::EnumSet;
use std::cell::Cell;
use std::cmp::min;
use std::rc::Rc;
use theme::{BorderStyle, ColorStyle, Effect, PaletteColor, Style, Theme};
use unicode_segmentation::UnicodeSegmentation;
use utils::lines::simple::prefix;
use vec::Vec2;
use with::With;

/// Convenient interface to draw on a subset of the screen.
pub struct Printer<'a> {
    /// Offset into the window this printer should start drawing at.
    pub offset: Vec2,

    /// Offset into the view for this printer.
    pub content_offset: Vec2,

    /// Size of the area we are allowed to draw on.
    ///
    /// Anything outside of this should be discarded.
    pub size: Vec2,

    /// Whether the view to draw is currently focused or not.
    pub focused: bool,

    /// Currently used theme
    pub theme: &'a Theme,

    /// `true` if nothing has been drawn yet.
    new: Rc<Cell<bool>>,

    /// Backend used to actually draw things
    backend: &'a Backend,
}

impl<'a> Clone for Printer<'a> {
    fn clone(&self) -> Self {
        Printer {
            offset: self.offset,
            content_offset: self.content_offset,
            size: self.size,
            focused: self.focused,
            theme: self.theme,
            backend: self.backend,
            new: Rc::clone(&self.new),
        }
    }
}

impl<'a> Printer<'a> {
    /// Creates a new printer on the given window.
    ///
    /// But nobody needs to know that.
    #[doc(hidden)]
    pub fn new<T: Into<Vec2>>(
        size: T, theme: &'a Theme, backend: &'a Backend
    ) -> Self {
        Printer {
            offset: Vec2::zero(),
            content_offset: Vec2::zero(),
            size: size.into(),
            focused: true,
            theme,
            new: Rc::new(Cell::new(true)),
            backend,
        }
    }

    /// Clear the screen.
    ///
    /// It will discard anything drawn before.
    ///
    /// Users rarely need to call this directly.
    pub fn clear(&self) {
        self.backend
            .clear(self.theme.palette[PaletteColor::Background]);
    }

    /// Returns `true` if nothing has been printed yet.
    pub fn is_new(&self) -> bool {
        self.new.get()
    }

    // TODO: use &mut self? We don't *need* it, but it may make sense.
    // We don't want people to start calling prints in parallel?
    /// Prints some text at the given position relative to the window.
    pub fn print<S: Into<Vec2>>(&self, pos: S, text: &str) {
        self.new.set(false);

        let p = pos.into();
        if p.y >= self.size.y || p.x >= self.size.x {
            return;
        }
        // Do we have enough room for the entire line?
        let room = self.size.x - p.x;
        // We want the number of CHARACTERS, not bytes.
        // (Actually we want the "width" of the string, see unicode-width)
        let prefix_len = prefix(text.graphemes(true), room, "").length;
        let text = &text[..prefix_len];

        let p = p + self.offset;
        self.backend.print_at(p, text);
    }

    /// Prints a vertical line using the given character.
    pub fn print_vline<T: Into<Vec2>>(&self, start: T, len: usize, c: &str) {
        self.new.set(false);

        let p = start.into();
        if p.y > self.size.y || p.x > self.size.x {
            return;
        }
        let len = min(len, self.size.y - p.y);

        let p = p + self.offset;
        for y in 0..len {
            self.backend.print_at(p + (0,y), c);
        }
    }

    /// Prints a horizontal line using the given character.
    pub fn print_hline<T: Into<Vec2>>(&self, start: T, len: usize, c: &str) {
        self.new.set(false);

        let p = start.into();
        if p.y > self.size.y || p.x > self.size.x {
            return;
        }
        let len = min(len, self.size.x - p.x);
        let text: String = ::std::iter::repeat(c).take(len).collect();

        let p = p + self.offset;
        self.backend.print_at(p, &text);
    }

    /// Call the given closure with a colored printer,
    /// that will apply the given color on prints.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cursive::Printer;
    /// # use cursive::theme;
    /// # use cursive::backend;
    /// # let b = backend::dummy::Backend::init();
    /// # let t = theme::load_default();
    /// # let printer = Printer::new((6,4), &t, &*b);
    /// printer.with_color(theme::ColorStyle::highlight(), |printer| {
    ///     printer.print((0,0), "This text is highlighted!");
    /// });
    /// ```
    pub fn with_color<F>(&self, c: ColorStyle, f: F)
    where
        F: FnOnce(&Printer),
    {
        let old = self.backend.set_color(c.resolve(&self.theme.palette));
        f(self);
        self.backend.set_color(old);
    }

    /// Call the given closure with a styled printer,
    /// that will apply the given style on prints.
    pub fn with_style<F, T>(&self, style: T, f: F)
    where
        F: FnOnce(&Printer),
        T: Into<Style>,
    {
        let style = style.into();

        let color = style.color;
        let effects = style.effects;

        // eprintln!("{:?}", effects);

        if let Some(color) = color {
            self.with_color(color, |printer| {
                printer.with_effects(effects, f);
            });
        } else {
            self.with_effects(effects, f);
        }
    }

    /// Call the given closure with a modified printer
    /// that will apply the given effect on prints.
    pub fn with_effect<F>(&self, effect: Effect, f: F)
    where
        F: FnOnce(&Printer),
    {
        self.backend.set_effect(effect);
        f(self);
        self.backend.unset_effect(effect);
    }

    /// Call the given closure with a modified printer
    /// that will apply each given effect on prints.
    pub fn with_effects<F>(&self, effects: EnumSet<Effect>, f: F)
    where
        F: FnOnce(&Printer),
    {
        match effects.iter().next() {
            None => f(self),
            Some(effect) => {
                let mut effects = effects;
                effects.remove(effect);

                self.with_effect(effect, |s| s.with_effects(effects, f));
            }
        }
    }

    /// Prints a rectangular box.
    ///
    /// If `invert` is `true`, and the theme uses `Outset` borders, then the
    /// box will use an "inset" style instead.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cursive::Printer;
    /// # use cursive::theme;
    /// # use cursive::backend;
    /// # let b = backend::dummy::Backend::init();
    /// # let t = theme::load_default();
    /// # let printer = Printer::new((6,4), &t, &*b);
    /// printer.print_box((0,0), (6,4), false);
    /// ```
    pub fn print_box<T: Into<Vec2>, S: Into<Vec2>>(
        &self, start: T, size: S, invert: bool
    ) {
        self.new.set(false);

        let start = start.into();
        let size = size.into();

        if size.x < 2 || size.y < 2 {
            return;
        }
        let size = size - (1, 1);

        self.with_high_border(invert, |s| {
            s.print(start, "┌");
            s.print(start + size.keep_y(), "└");
            s.print_hline(start + (1, 0), size.x - 1, "─");
            s.print_vline(start + (0, 1), size.y - 1, "│");
        });

        self.with_low_border(invert, |s| {
            s.print(start + size.keep_x(), "┐");
            s.print(start + size, "┘");
            s.print_hline(
                start + (1, 0) + size.keep_y(),
                size.x - 1,
                "─",
            );
            s.print_vline(
                start + (0, 1) + size.keep_x(),
                size.y - 1,
                "│",
            );
        });
    }

    /// Runs the given function using a color depending on the theme.
    ///
    /// * If the theme's borders is `None`, return without calling `f`.
    /// * If the theme's borders is "outset" and `invert` is `false`,
    ///   use `ColorStyle::Tertiary`.
    /// * Otherwise, use `ColorStyle::Primary`.
    pub fn with_high_border<F>(&self, invert: bool, f: F)
    where
        F: FnOnce(&Printer),
    {
        let color = match self.theme.borders {
            BorderStyle::None => return,
            BorderStyle::Outset if !invert => ColorStyle::tertiary(),
            _ => ColorStyle::primary(),
        };

        self.with_color(color, f);
    }

    /// Runs the given function using a color depending on the theme.
    ///
    /// * If the theme's borders is `None`, return without calling `f`.
    /// * If the theme's borders is "outset" and `invert` is `true`,
    ///   use `ColorStyle::tertiary()`.
    /// * Otherwise, use `ColorStyle::primary()`.
    pub fn with_low_border<F>(&self, invert: bool, f: F)
    where
        F: FnOnce(&Printer),
    {
        let color = match self.theme.borders {
            BorderStyle::None => return,
            BorderStyle::Outset if invert => ColorStyle::tertiary(),
            _ => ColorStyle::primary(),
        };

        self.with_color(color, f);
    }

    /// Apply a selection style and call the given function.
    ///
    /// * If `selection` is `false`, simply uses `ColorStyle::primary()`.
    /// * If `selection` is `true`:
    ///     * If the printer currently has the focus,
    ///       uses `ColorStyle::highlight()`.
    ///     * Otherwise, uses `ColorStyle::highlight_inactive()`.
    pub fn with_selection<F: FnOnce(&Printer)>(&self, selection: bool, f: F) {
        self.with_color(
            if selection {
                if self.focused {
                    ColorStyle::highlight()
                } else {
                    ColorStyle::highlight_inactive()
                }
            } else {
                ColorStyle::primary()
            },
            f,
        );
    }

    /// Prints a horizontal delimiter with side border `├` and `┤`.
    pub fn print_hdelim<T>(&self, start: T, len: usize)
    where
        T: Into<Vec2>,
    {
        let start = start.into();
        self.print(start, "├");
        self.print_hline(start + (1, 0), len.saturating_sub(2), "─");
        self.print(start + (len.saturating_sub(1), 0), "┤");
    }

    /// Returns a sub-printer with the given offset.
    pub fn offset<S>(&self, offset: S) -> Printer
    where
        S: Into<Vec2>,
    {
        let offset = offset.into();
        self.clone().with(|s| {
            let consumed = Vec2::min(s.content_offset, offset);

            s.content_offset = s.content_offset - consumed;
            s.offset = s.offset + offset - consumed;
            s.size = s.size.saturating_sub(offset);
        })
    }

    /// Returns a new sub-printer inheriting the given focus.
    ///
    /// If `self` is focused and `focused == true`, the child will be focused.
    ///
    /// Otherwise, he will be unfocused.
    pub fn focused(&self, focused: bool) -> Self {
        self.clone().with(|s| {
            s.focused &= focused;
        })
    }

    /// Returns a new sub-printer with a cropped area.
    ///
    /// The new printer size will be the minimum of `size` and its current size.
    ///
    /// Any size reduction happens at the bottom-right.
    pub fn cropped<S>(&self, size: S) -> Self
    where
        S: Into<Vec2>,
    {
        self.clone().with(|s| {
            s.size = Vec2::min(s.size, size);
        })
    }

    /// Returns a new sub-printer with a shrinked area.
    ///
    /// The printer size will be reduced by the given border from the bottom-right.
    pub fn shrinked<S>(&self, borders: S) -> Self
    where
        S: Into<Vec2>,
    {
        self.cropped(self.size.saturating_sub(borders))
    }

    /// Returns a new sub-printer with a content offset.
    pub fn content_offset<S>(&self, offset: S) -> Self
    where
        S: Into<Vec2>,
    {
        self.clone().with(|s| {
            s.content_offset = s.content_offset + offset;
        })
    }
}
<commit_msg>Remove Printer::is_new<commit_after>//! Provide higher-level abstraction to draw things on backends.

use backend::Backend;
use enumset::EnumSet;
use std::cmp::min;
use theme::{BorderStyle, ColorStyle, Effect, PaletteColor, Style, Theme};
use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
use utils::lines::simple::prefix;
use vec::Vec2;
use with::With;

/// Convenient interface to draw on a subset of the screen.
///
/// The area it can print on is defined by `offset` and `size`.
///
/// The part of the content it will print there is defined by `content_offset`
/// and `size`.
pub struct Printer<'a> {
    /// Offset into the window this printer should start drawing at.
    ///
    /// Printing at `x` will really print at `x + offset`.
    pub offset: Vec2,

    /// Size of the area we are allowed to draw on.
    ///
    /// Anything outside of this should be discarded.
    pub size: Vec2,

    /// Offset into the view for this printer.
    ///
    /// Printing at `x`, will really print at `x - content_offset`.
    pub content_offset: Vec2,

    /// Whether the view to draw is currently focused or not.
    pub focused: bool,

    /// Currently used theme
    pub theme: &'a Theme,

    /// Backend used to actually draw things
    backend: &'a Backend,
}

impl<'a> Clone for Printer<'a> {
    fn clone(&self) -> Self {
        Printer {
            offset: self.offset,
            content_offset: self.content_offset,
            size: self.size,
            focused: self.focused,
            theme: self.theme,
            backend: self.backend,
        }
    }
}

impl<'a> Printer<'a> {
    /// Creates a new printer on the given window.
    ///
    /// But nobody needs to know that.
    #[doc(hidden)]
    pub fn new<T: Into<Vec2>>(
        size: T, theme: &'a Theme, backend: &'a Backend
    ) -> Self {
        Printer {
            offset: Vec2::zero(),
            content_offset: Vec2::zero(),
            size: size.into(),
            focused: true,
            theme,
            backend,
        }
    }

    /// Clear the screen.
    ///
    /// It will discard anything drawn before.
    ///
    /// Users rarely need to call this directly.
    pub fn clear(&self) {
        self.backend
            .clear(self.theme.palette[PaletteColor::Background]);
    }

    // TODO: use &mut self? We don't *need* it, but it may make sense.
    // We don't want people to start calling prints in parallel?
    /// Prints some text at the given position relative to the window.
    pub fn print<S: Into<Vec2>>(&self, pos: S, text: &str) {
        let pos = pos.into();
        if !pos.fits_in(self.size) {
            return;
        }
        // Do we have enough room for the entire line?
        let room = self.size.x - pos.x;

        // Drop the end of the text if it's too long
        // We want the number of CHARACTERS, not bytes.
        // (Actually we want the "width" of the string, see unicode-width)
        let prefix_len = prefix(text.graphemes(true), room, "").length;
        let text = &text[..prefix_len];

        let pos = pos + self.offset;
        self.backend.print_at(pos, text);
    }

    /// Prints a vertical line using the given character.
    pub fn print_vline<T: Into<Vec2>>(&self, start: T, len: usize, c: &str) {
        let start = start.into();
        if !start.fits_in(self.size) {
            return;
        }
        let len = min(len, self.size.y - start.y);

        let start = start + self.offset;
        for y in 0..len {
            self.backend.print_at(start + (0,y), c);
        }
    }

    /// Prints a horizontal line using the given character.
    pub fn print_hline<T: Into<Vec2>>(&self, start: T, len: usize, c: &str) {
        let start = start.into();
        if !start.fits_in(self.size) {
            return;
        }
        let len = min(len, (self.size.x - start.x) / c.width());
        let text: String = ::std::iter::repeat(c).take(len).collect();

        let start = start + self.offset;
        self.backend.print_at(start, &text);
    }

    /// Call the given closure with a colored printer,
    /// that will apply the given color on prints.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cursive::Printer;
    /// # use cursive::theme;
    /// # use cursive::backend;
    /// # let b = backend::dummy::Backend::init();
    /// # let t = theme::load_default();
    /// # let printer = Printer::new((6,4), &t, &*b);
    /// printer.with_color(theme::ColorStyle::highlight(), |printer| {
    ///     printer.print((0,0), "This text is highlighted!");
    /// });
    /// ```
    pub fn with_color<F>(&self, c: ColorStyle, f: F)
    where
        F: FnOnce(&Printer),
    {
        let old = self.backend.set_color(c.resolve(&self.theme.palette));
        f(self);
        self.backend.set_color(old);
    }

    /// Call the given closure with a styled printer,
    /// that will apply the given style on prints.
    pub fn with_style<F, T>(&self, style: T, f: F)
    where
        F: FnOnce(&Printer),
        T: Into<Style>,
    {
        let style = style.into();

        let color = style.color;
        let effects = style.effects;

        // eprintln!("{:?}", effects);

        if let Some(color) = color {
            self.with_color(color, |printer| {
                printer.with_effects(effects, f);
            });
        } else {
            self.with_effects(effects, f);
        }
    }

    /// Call the given closure with a modified printer
    /// that will apply the given effect on prints.
    pub fn with_effect<F>(&self, effect: Effect, f: F)
    where
        F: FnOnce(&Printer),
    {
        self.backend.set_effect(effect);
        f(self);
        self.backend.unset_effect(effect);
    }

    /// Call the given closure with a modified printer
    /// that will apply each given effect on prints.
    pub fn with_effects<F>(&self, effects: EnumSet<Effect>, f: F)
    where
        F: FnOnce(&Printer),
    {
        match effects.iter().next() {
            None => f(self),
            Some(effect) => {
                let mut effects = effects;
                effects.remove(effect);

                self.with_effect(effect, |s| s.with_effects(effects, f));
            }
        }
    }

    /// Prints a rectangular box.
    ///
    /// If `invert` is `true`, and the theme uses `Outset` borders, then the
    /// box will use an "inset" style instead.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cursive::Printer;
    /// # use cursive::theme;
    /// # use cursive::backend;
    /// # let b = backend::dummy::Backend::init();
    /// # let t = theme::load_default();
    /// # let printer = Printer::new((6,4), &t, &*b);
    /// printer.print_box((0,0), (6,4), false);
    /// ```
    pub fn print_box<T: Into<Vec2>, S: Into<Vec2>>(
        &self, start: T, size: S, invert: bool
    ) {
        let start = start.into();
        let size = size.into();

        if size.x < 2 || size.y < 2 {
            return;
        }
        let size = size - (1, 1);

        self.with_high_border(invert, |s| {
            s.print(start, "┌");
            s.print(start + size.keep_y(), "└");
            s.print_hline(start + (1, 0), size.x - 1, "─");
            s.print_vline(start + (0, 1), size.y - 1, "│");
        });

        self.with_low_border(invert, |s| {
            s.print(start + size.keep_x(), "┐");
            s.print(start + size, "┘");
            s.print_hline(
                start + (1, 0) + size.keep_y(),
                size.x - 1,
                "─",
            );
            s.print_vline(
                start + (0, 1) + size.keep_x(),
                size.y - 1,
                "│",
            );
        });
    }

    /// Runs the given function using a color depending on the theme.
    ///
    /// * If the theme's borders is `None`, return without calling `f`.
    /// * If the theme's borders is "outset" and `invert` is `false`,
    ///   use `ColorStyle::Tertiary`.
    /// * Otherwise, use `ColorStyle::Primary`.
    pub fn with_high_border<F>(&self, invert: bool, f: F)
    where
        F: FnOnce(&Printer),
    {
        let color = match self.theme.borders {
            BorderStyle::None => return,
            BorderStyle::Outset if !invert => ColorStyle::tertiary(),
            _ => ColorStyle::primary(),
        };

        self.with_color(color, f);
    }

    /// Runs the given function using a color depending on the theme.
    ///
    /// * If the theme's borders is `None`, return without calling `f`.
    /// * If the theme's borders is "outset" and `invert` is `true`,
    ///   use `ColorStyle::tertiary()`.
    /// * Otherwise, use `ColorStyle::primary()`.
    pub fn with_low_border<F>(&self, invert: bool, f: F)
    where
        F: FnOnce(&Printer),
    {
        let color = match self.theme.borders {
            BorderStyle::None => return,
            BorderStyle::Outset if invert => ColorStyle::tertiary(),
            _ => ColorStyle::primary(),
        };

        self.with_color(color, f);
    }

    /// Apply a selection style and call the given function.
    ///
    /// * If `selection` is `false`, simply uses `ColorStyle::primary()`.
    /// * If `selection` is `true`:
    ///     * If the printer currently has the focus,
    ///       uses `ColorStyle::highlight()`.
    ///     * Otherwise, uses `ColorStyle::highlight_inactive()`.
    pub fn with_selection<F: FnOnce(&Printer)>(&self, selection: bool, f: F) {
        self.with_color(
            if selection {
                if self.focused {
                    ColorStyle::highlight()
                } else {
                    ColorStyle::highlight_inactive()
                }
            } else {
                ColorStyle::primary()
            },
            f,
        );
    }

    /// Prints a horizontal delimiter with side border `├` and `┤`.
    pub fn print_hdelim<T>(&self, start: T, len: usize)
    where
        T: Into<Vec2>,
    {
        let start = start.into();
        self.print(start, "├");
        self.print_hline(start + (1, 0), len.saturating_sub(2), "─");
        self.print(start + (len.saturating_sub(1), 0), "┤");
    }

    /// Returns a sub-printer with the given offset.
    pub fn offset<S>(&self, offset: S) -> Printer
    where
        S: Into<Vec2>,
    {
        let offset = offset.into();
        self.clone().with(|s| {
            let consumed = Vec2::min(s.content_offset, offset);

            s.content_offset = s.content_offset - consumed;
            s.offset = s.offset + offset - consumed;
            s.size = s.size.saturating_sub(offset);
        })
    }

    /// Returns a new sub-printer inheriting the given focus.
    ///
    /// If `self` is focused and `focused == true`, the child will be focused.
    ///
    /// Otherwise, he will be unfocused.
    pub fn focused(&self, focused: bool) -> Self {
        self.clone().with(|s| {
            s.focused &= focused;
        })
    }

    /// Returns a new sub-printer with a cropped area.
    ///
    /// The new printer size will be the minimum of `size` and its current size.
    ///
    /// Any size reduction happens at the bottom-right.
    pub fn cropped<S>(&self, size: S) -> Self
    where
        S: Into<Vec2>,
    {
        self.clone().with(|s| {
            s.size = Vec2::min(s.size, size);
        })
    }

    /// Returns a new sub-printer with a shrinked area.
    ///
    /// The printer size will be reduced by the given border from the bottom-right.
    pub fn shrinked<S>(&self, borders: S) -> Self
    where
        S: Into<Vec2>,
    {
        self.cropped(self.size.saturating_sub(borders))
    }

    /// Returns a new sub-printer with a content offset.
    pub fn content_offset<S>(&self, offset: S) -> Self
    where
        S: Into<Vec2>,
    {
        self.clone().with(|s| {
            s.content_offset = s.content_offset + offset;
        })
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;

use std::cmp::Ordering;
use std::collections::HashMap;
use std::hash::Hash;
use std::io::prelude::*;
use std::fs::File;

use self::rustc_serialize::json;

use ngrams::ngrams;

pub type StringCountPair = (String, u64);
pub struct Profile {
    pub ngram_ranks: HashMap<String, usize>,
}

impl Profile {
    pub fn build_from_text(text: &str) -> Profile {
        let mut ngram_counts = HashMap::new();
        for n in 1..6 {
            for ngram in ngrams(text, n) {
                *ngram_counts.entry(ngram).or_insert(0u64) += 1;
            }
        }

        let mut ngrams_and_counts = vec_from_hashmap(&ngram_counts);
        ngrams_and_counts.sort_by(cmp_counts_reverse);

        let mut ngram_ranks = HashMap::new();
        for (index, item) in ngrams_and_counts.iter().enumerate() {
            ngram_ranks.insert((*item).clone().0, index);
        }

        Profile { ngram_ranks: ngram_ranks }
    }

    pub fn load_from_file(path: &str) -> Profile {
        let mut f = File::open(path).unwrap();
        let mut encoded_profile = String::new();
        f.read_to_string(&mut encoded_profile);
        let ngram_ranks = json::decode(&encoded_profile).unwrap();
        Profile { ngram_ranks: ngram_ranks }
    }

    pub fn save_to_file(self, path: &str) {
        let encoded_profile = json::encode(&self.ngram_ranks).unwrap();
        let mut f = File::create(path).unwrap();
        f.write_all(encoded_profile.as_bytes()).unwrap();
    }
}

// useful utils

fn vec_from_hashmap<K, V> (hashmap: &HashMap<K, V>) -> Vec<(K, V)>
         where K: Eq + Hash + Clone, V: Clone {
    let mut vec: Vec<(K, V)> = Vec::new();
    for (key, value) in hashmap.iter() {
        let item = ((*key).clone(), (*value).clone());
        vec.push(item);
    }
    vec
}

fn cmp_counts_reverse(a: &StringCountPair, b: &StringCountPair) -> Ordering {
    b.1.cmp(&a.1)
}
<commit_msg>Use usize everywhere, it's simpler<commit_after>extern crate rustc_serialize;

use std::cmp::Ordering;
use std::collections::HashMap;
use std::hash::Hash;
use std::io::prelude::*;
use std::fs::File;

use self::rustc_serialize::json;

use ngrams::ngrams;

pub type StringCountPair = (String, usize);
pub struct Profile {
    pub ngram_ranks: HashMap<String, usize>,
}

impl Profile {
    pub fn build_from_text(text: &str) -> Profile {
        let mut ngram_counts = HashMap::new();
        for n in 1..6 {
            for ngram in ngrams(text, n) {
                *ngram_counts.entry(ngram).or_insert(0usize) += 1;
            }
        }

        let mut ngrams_and_counts = vec_from_hashmap(&ngram_counts);
        ngrams_and_counts.sort_by(cmp_counts_reverse);

        let mut ngram_ranks = HashMap::new();
        for (index, item) in ngrams_and_counts.iter().enumerate() {
            ngram_ranks.insert((*item).clone().0, index);
        }

        Profile { ngram_ranks: ngram_ranks }
    }

    pub fn load_from_file(path: &str) -> Profile {
        let mut f = File::open(path).unwrap();
        let mut encoded_profile = String::new();
        f.read_to_string(&mut encoded_profile);
        let ngram_ranks = json::decode(&encoded_profile).unwrap();
        Profile { ngram_ranks: ngram_ranks }
    }

    pub fn save_to_file(self, path: &str) {
        let encoded_profile = json::encode(&self.ngram_ranks).unwrap();
        let mut f = File::create(path).unwrap();
        f.write_all(encoded_profile.as_bytes()).unwrap();
    }
}

// useful utils

fn vec_from_hashmap<K, V> (hashmap: &HashMap<K, V>) -> Vec<(K, V)>
         where K: Eq + Hash + Clone, V: Clone {
    let mut vec: Vec<(K, V)> = Vec::new();
    for (key, value) in hashmap.iter() {
        let item = ((*key).clone(), (*value).clone());
        vec.push(item);
    }
    vec
}

fn cmp_counts_reverse(a: &StringCountPair, b: &StringCountPair) -> Ordering {
    b.1.cmp(&a.1)
}
<|endoftext|>


<commit_before>//! Checks for usage of &Vec[_] and &String
//!
//! This lint is **warn** by default

use rustc::plugin::Registry;
use rustc::lint::*;
use rustc::middle::const_eval::lookup_const_by_id;
use rustc::middle::def::*;
use syntax::ast::*;
use syntax::ast_util::{is_comparison_binop, binop_to_string};
use syntax::ptr::P;
use syntax::codemap::Span;
use types::match_ty_unwrap;

declare_lint! {
    pub PTR_ARG,
    Allow,
    "Warn on declaration of a &Vec- or &String-typed method argument"
}

#[derive(Copy,Clone)]
pub struct PtrArg;

impl LintPass for PtrArg {
    fn get_lints(&self) -> LintArray {
        lint_array!(PTR_ARG)
    }

    fn check_item(&mut self, cx: &Context, item: &Item) {
		if let &ItemFn(ref decl, _, _, _, _) = &item.node {
			check_fn(cx, decl);
		}
	}

    fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) {
		if let &MethodImplItem(ref sig, _) = &item.node {
			check_fn(cx, &sig.decl);
		}
	}

	fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) {
		if let &MethodTraitItem(ref sig, _) = &item.node {
			check_fn(cx, &sig.decl);
		}
	}
}

fn check_fn(cx: &Context, decl: &FnDecl) {
	for arg in &decl.inputs {
		match &arg.ty.node {
			&TyPtr(ref p) | &TyRptr(_, ref p) =>
				check_ptr_subtype(cx, arg.ty.span, &p.ty),
			_ => ()
		}
	}
}

fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) {
	match_ty_unwrap(ty, &["Vec"]).map_or_else(|| match_ty_unwrap(ty,
			&["String"]).map_or((), |_| {
		cx.span_lint(PTR_ARG, span,
			"Writing '&String' instead of '&str' involves a new Object \
			where a slices will do. Consider changing the type to &str")
	}), |_| cx.span_lint(PTR_ARG, span, "Writing '&Vec<_>' instead of \
			'&[_]' involves one more reference and cannot be used with \
			non-vec-based slices. Consider changing the type to &[...]")
	)
}
<commit_msg>fixed issue #69<commit_after>//! Checks for usage of &Vec[_] and &String
//!
//! This lint is **warn** by default

use rustc::plugin::Registry;
use rustc::lint::*;
use rustc::middle::const_eval::lookup_const_by_id;
use rustc::middle::def::*;
use syntax::ast::*;
use syntax::ast_util::{is_comparison_binop, binop_to_string};
use syntax::ptr::P;
use syntax::codemap::Span;
use types::match_ty_unwrap;

declare_lint! {
    pub PTR_ARG,
    Allow,
    "Warn on declaration of a &Vec- or &String-typed method argument"
}

#[derive(Copy,Clone)]
pub struct PtrArg;

impl LintPass for PtrArg {
    fn get_lints(&self) -> LintArray {
        lint_array!(PTR_ARG)
    }

    fn check_item(&mut self, cx: &Context, item: &Item) {
		if let &ItemFn(ref decl, _, _, _, _, _) = &item.node {
			check_fn(cx, decl);
		}
	}

    fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) {
		if let &MethodImplItem(ref sig, _) = &item.node {
			check_fn(cx, &sig.decl);
		}
	}

	fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) {
		if let &MethodTraitItem(ref sig, _) = &item.node {
			check_fn(cx, &sig.decl);
		}
	}
}

fn check_fn(cx: &Context, decl: &FnDecl) {
	for arg in &decl.inputs {
		match &arg.ty.node {
			&TyPtr(ref p) | &TyRptr(_, ref p) =>
				check_ptr_subtype(cx, arg.ty.span, &p.ty),
			_ => ()
		}
	}
}

fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) {
	match_ty_unwrap(ty, &["Vec"]).map_or_else(|| match_ty_unwrap(ty,
			&["String"]).map_or((), |_| {
		cx.span_lint(PTR_ARG, span,
			"Writing '&String' instead of '&str' involves a new Object \
			where a slices will do. Consider changing the type to &str")
	}), |_| cx.span_lint(PTR_ARG, span, "Writing '&Vec<_>' instead of \
			'&[_]' involves one more reference and cannot be used with \
			non-vec-based slices. Consider changing the type to &[...]")
	)
}
<|endoftext|>


<commit_before>
use ffi;
use super::c64;
use super::util::FFTW_MUTEX;

use std::slice::{from_raw_parts, from_raw_parts_mut};
use std::os::raw::c_void;
use std::ops::{Index, IndexMut};
use std::slice::{Iter, IterMut};

pub struct RawVec<T> {
    n: usize,
    data: *mut T,
}

impl<T> RawVec<T> {
    pub fn as_slice(&self) -> &[T] { unsafe { from_raw_parts(self.data, self.n) } }
    pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { from_raw_parts_mut(self.data, self.n) } }

    pub fn as_ptr(&self) -> *const T { self.data }
    pub fn as_mut_ptr(&mut self) -> *mut T { self.data }

    pub fn iter<'a>(&'a self) -> Iter<'a, T> { self.as_slice().iter() }
    pub fn iter_mut<'a>(&'a mut self) -> IterMut<'a, T> { self.as_mut_slice().iter_mut() }
}

impl<T> Drop for RawVec<T> {
    fn drop(&mut self) {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe { ffi::fftw_free(self.data as *mut c_void) };
        drop(lock);
    }
}

impl RawVec<f64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_real(n) };
        drop(lock);
        RawVec { n: n, data: ptr }
    }
}

impl RawVec<c64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_complex(n) } as *mut c64;
        drop(lock);
        RawVec { n: n, data: ptr }
    }
}

impl<T> Index<isize> for RawVec<T> {
    type Output = T;
    fn index(&self, index: isize) -> &Self::Output { unsafe { &*self.data.offset(index) } }
}

impl<T> IndexMut<isize> for RawVec<T> {
    fn index_mut(&mut self, index: isize) -> &mut Self::Output { unsafe { &mut *self.data.offset(index) } }
}
<commit_msg>Add method `len()` for RawVec<commit_after>
use ffi;
use super::c64;
use super::util::FFTW_MUTEX;

use std::slice::{from_raw_parts, from_raw_parts_mut};
use std::os::raw::c_void;
use std::ops::{Index, IndexMut};
use std::slice::{Iter, IterMut};

pub struct RawVec<T> {
    n: usize,
    data: *mut T,
}

impl<T> RawVec<T> {
    pub fn as_slice(&self) -> &[T] { unsafe { from_raw_parts(self.data, self.n) } }
    pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { from_raw_parts_mut(self.data, self.n) } }

    pub fn as_ptr(&self) -> *const T { self.data }
    pub fn as_mut_ptr(&mut self) -> *mut T { self.data }

    pub fn len(&self) -> usize { self.n }

    pub fn iter<'a>(&'a self) -> Iter<'a, T> { self.as_slice().iter() }
    pub fn iter_mut<'a>(&'a mut self) -> IterMut<'a, T> { self.as_mut_slice().iter_mut() }
}

impl<T> Drop for RawVec<T> {
    fn drop(&mut self) {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe { ffi::fftw_free(self.data as *mut c_void) };
        drop(lock);
    }
}

impl RawVec<f64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_real(n) };
        drop(lock);
        RawVec { n: n, data: ptr }
    }
}

impl RawVec<c64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_complex(n) } as *mut c64;
        drop(lock);
        RawVec { n: n, data: ptr }
    }
}

impl<T> Index<isize> for RawVec<T> {
    type Output = T;
    fn index(&self, index: isize) -> &Self::Output { unsafe { &*self.data.offset(index) } }
}

impl<T> IndexMut<isize> for RawVec<T> {
    fn index_mut(&mut self, index: isize) -> &mut Self::Output { unsafe { &mut *self.data.offset(index) } }
}
<|endoftext|>