<commit_before>/* TOOD: Implement for other kqueue based systems
 */

use {Errno, Result};
#[cfg(not(target_os = "netbsd"))]
use libc::{timespec, time_t, c_int, c_long, intptr_t, uintptr_t};
#[cfg(target_os = "netbsd")]
use libc::{timespec, time_t, c_long, intptr_t, uintptr_t, size_t};
use libc;
use std::os::unix::io::RawFd;
use std::ptr;
use std::mem;

// Redefine kevent in terms of programmer-friendly enums and bitfields.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct KEvent {
    kevent: libc::kevent,
}

#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
          target_os = "ios", target_os = "macos",
          target_os = "openbsd"))]
type type_of_udata = *mut libc::c_void;
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
          target_os = "ios", target_os = "macos"))]
type type_of_data = intptr_t;
#[cfg(any(target_os = "netbsd"))]
type type_of_udata = intptr_t;
#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
type type_of_data = libc::int64_t;

#[cfg(target_os = "netbsd")]
type type_of_event_filter = u32;
#[cfg(not(target_os = "netbsd"))]
type type_of_event_filter = i16;
libc_enum! {
    #[cfg_attr(target_os = "netbsd", repr(u32))]
    #[cfg_attr(not(target_os = "netbsd"), repr(i16))]
    pub enum EventFilter {
        EVFILT_AIO,
        /// Returns whenever there is no remaining data in the write buffer
        #[cfg(target_os = "freebsd")]
        EVFILT_EMPTY,
        #[cfg(target_os = "dragonfly")]
        EVFILT_EXCEPT,
        #[cfg(any(target_os = "dragonfly",
                  target_os = "freebsd",
                  target_os = "ios",
                  target_os = "macos"))]
        EVFILT_FS,
        #[cfg(target_os = "freebsd")]
        EVFILT_LIO,
        #[cfg(any(target_os = "ios", target_os = "macos"))]
        EVFILT_MACHPORT,
        EVFILT_PROC,
        /// Returns events associated with the process referenced by a given
        /// process descriptor, created by `pdfork()`. The events to monitor are:
        ///
        /// - NOTE_EXIT: the process has exited. The exit status will be stored in data.
        #[cfg(target_os = "freebsd")]
        EVFILT_PROCDESC,
        EVFILT_READ,
        /// Returns whenever an asynchronous `sendfile()` call completes.
        #[cfg(target_os = "freebsd")]
        EVFILT_SENDFILE,
        EVFILT_SIGNAL,
        EVFILT_TIMER,
        #[cfg(any(target_os = "dragonfly",
                  target_os = "freebsd",
                  target_os = "ios",
                  target_os = "macos"))]
        EVFILT_USER,
        #[cfg(any(target_os = "ios", target_os = "macos"))]
        EVFILT_VM,
        EVFILT_VNODE,
        EVFILT_WRITE,
    }
}

#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
          target_os = "ios", target_os = "macos",
          target_os = "openbsd"))]
pub type type_of_event_flag = u16;
#[cfg(any(target_os = "netbsd"))]
pub type type_of_event_flag = u32;
libc_bitflags!{
    pub struct EventFlag: type_of_event_flag {
        EV_ADD;
        EV_CLEAR;
        EV_DELETE;
        EV_DISABLE;
        #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
                  target_os = "ios", target_os = "macos",
                  target_os = "netbsd", target_os = "openbsd"))]
        EV_DISPATCH;
        #[cfg(target_os = "freebsd")]
        EV_DROP;
        EV_ENABLE;
        EV_EOF;
        EV_ERROR;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        EV_FLAG0;
        EV_FLAG1;
        #[cfg(target_os = "dragonfly")]
        EV_NODATA;
        EV_ONESHOT;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        EV_OOBAND;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        EV_POLL;
        #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
                  target_os = "ios", target_os = "macos",
                  target_os = "netbsd", target_os = "openbsd"))]
        EV_RECEIPT;
        EV_SYSFLAGS;
    }
}

libc_bitflags!(
    pub struct FilterFlag: u32 {
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_ABSOLUTE;
        NOTE_ATTRIB;
        NOTE_CHILD;
        NOTE_DELETE;
        #[cfg(target_os = "openbsd")]
        NOTE_EOF;
        NOTE_EXEC;
        NOTE_EXIT;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
        #[allow(deprecated)]
        NOTE_EXIT_REPARENTED;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_EXITSTATUS;
        NOTE_EXTEND;
        #[cfg(any(target_os = "macos",
                  target_os = "ios",
                  target_os = "freebsd",
                  target_os = "dragonfly"))]
        NOTE_FFAND;
        #[cfg(any(target_os = "macos",
                  target_os = "ios",
                  target_os = "freebsd",
                  target_os = "dragonfly"))]
        NOTE_FFCOPY;
        #[cfg(any(target_os = "macos",
                  target_os = "ios",
                  target_os = "freebsd",
                  target_os = "dragonfly"))]
        NOTE_FFCTRLMASK;
        #[cfg(any(target_os = "macos",
                  target_os = "ios",
                  target_os = "freebsd",
                  target_os = "dragonfly"))]
        NOTE_FFLAGSMASK;
        #[cfg(any(target_os = "macos",
                  target_os = "ios",
                  target_os = "freebsd",
                  target_os = "dragonfly"))]
        NOTE_FFNOP;
        #[cfg(any(target_os = "macos",
                  target_os = "ios",
                  target_os = "freebsd",
                  target_os = "dragonfly"))]
        NOTE_FFOR;
        NOTE_FORK;
        NOTE_LINK;
        NOTE_LOWAT;
        #[cfg(target_os = "freebsd")]
        NOTE_MSECONDS;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_NONE;
        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
        NOTE_NSECONDS;
        #[cfg(target_os = "dragonfly")]
        NOTE_OOB;
        NOTE_PCTRLMASK;
        NOTE_PDATAMASK;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
        #[allow(deprecated)]
        NOTE_REAP;
        NOTE_RENAME;
        NOTE_REVOKE;
        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
        NOTE_SECONDS;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_SIGNAL;
        NOTE_TRACK;
        NOTE_TRACKERR;
        #[cfg(any(target_os = "macos",
                  target_os = "ios",
                  target_os = "freebsd",
                  target_os = "dragonfly"))]
        NOTE_TRIGGER;
        #[cfg(target_os = "openbsd")]
        NOTE_TRUNCATE;
        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
        NOTE_USECONDS;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_VM_ERROR;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_VM_PRESSURE;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_VM_PRESSURE_SUDDEN_TERMINATE;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_VM_PRESSURE_TERMINATE;
        NOTE_WRITE;
    }
);

pub fn kqueue() -> Result<RawFd> {
    let res = unsafe { libc::kqueue() };

    Errno::result(res)
}

// KEvent can't derive Send because on some operating systems, udata is defined
// as a void*.  However, KEvent's public API always treats udata as an intptr_t,
// which is safe to Send.
unsafe impl Send for KEvent {
}

impl KEvent {
    pub fn new(ident: uintptr_t, filter: EventFilter, flags: EventFlag,
               fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent {
        KEvent { kevent: libc::kevent {
            ident,
            filter: filter as type_of_event_filter,
            flags: flags.bits(),
            fflags: fflags.bits(),
            data: data as type_of_data,
            udata: udata as type_of_udata
        } }
    }

    pub fn ident(&self) -> uintptr_t {
        self.kevent.ident
    }

    pub fn filter(&self) -> EventFilter {
        unsafe { mem::transmute(self.kevent.filter as type_of_event_filter) }
    }

    pub fn flags(&self) -> EventFlag {
        EventFlag::from_bits(self.kevent.flags).unwrap()
    }

    pub fn fflags(&self) -> FilterFlag {
        FilterFlag::from_bits(self.kevent.fflags).unwrap()
    }

    pub fn data(&self) -> intptr_t {
        self.kevent.data as intptr_t
    }

    pub fn udata(&self) -> intptr_t {
        self.kevent.udata as intptr_t
    }
}

pub fn kevent(kq: RawFd,
              changelist: &[KEvent],
              eventlist: &mut [KEvent],
              timeout_ms: usize) -> Result<usize> {

    // Convert ms to timespec
    let timeout = timespec {
        tv_sec: (timeout_ms / 1000) as time_t,
        tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long
    };

    kevent_ts(kq, changelist, eventlist, Some(timeout))
}

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "openbsd"))]
type type_of_nchanges = c_int;
#[cfg(target_os = "netbsd")]
type type_of_nchanges = size_t;

pub fn kevent_ts(kq: RawFd,
              changelist: &[KEvent],
              eventlist: &mut [KEvent],
              timeout_opt: Option<timespec>) -> Result<usize> {

    let res = unsafe {
        libc::kevent(
            kq,
            changelist.as_ptr() as *const libc::kevent,
            changelist.len() as type_of_nchanges,
            eventlist.as_mut_ptr() as *mut libc::kevent,
            eventlist.len() as type_of_nchanges,
            if let Some(ref timeout) = timeout_opt {timeout as *const timespec} else {ptr::null()})
    };

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

#[inline]
pub fn ev_set(ev: &mut KEvent,
              ident: usize,
              filter: EventFilter,
              flags: EventFlag,
              fflags: FilterFlag,
              udata: intptr_t) {

    ev.kevent.ident  = ident as uintptr_t;
    ev.kevent.filter = filter as type_of_event_filter;
    ev.kevent.flags  = flags.bits();
    ev.kevent.fflags = fflags.bits();
    ev.kevent.data   = 0;
    ev.kevent.udata  = udata as type_of_udata;
}

#[test]
fn test_struct_kevent() {
    let udata : intptr_t = 12345;

    let actual = KEvent::new(0xdead_beef,
                             EventFilter::EVFILT_READ,
                             EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
                             FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
                             0x1337,
                             udata);
    assert_eq!(0xdead_beef, actual.ident());
    assert_eq!(libc::EVFILT_READ, actual.filter() as type_of_event_filter);
    assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits());
    assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits());
    assert_eq!(0x1337, actual.data() as type_of_data);
    assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata);
    assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>());
}
<commit_msg>Fix use of deprecated libc type, needed in order to run the tests successfully. This type was deprecated in libc 0.2.55.<commit_after>/* TOOD: Implement for other kqueue based systems
 */

use {Errno, Result};
#[cfg(not(target_os = "netbsd"))]
use libc::{timespec, time_t, c_int, c_long, intptr_t, uintptr_t};
#[cfg(target_os = "netbsd")]
use libc::{timespec, time_t, c_long, intptr_t, uintptr_t, size_t};
use libc;
use std::os::unix::io::RawFd;
use std::ptr;
use std::mem;

// Redefine kevent in terms of programmer-friendly enums and bitfields.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct KEvent {
    kevent: libc::kevent,
}

#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
          target_os = "ios", target_os = "macos",
          target_os = "openbsd"))]
type type_of_udata = *mut libc::c_void;
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
          target_os = "ios", target_os = "macos"))]
type type_of_data = intptr_t;
#[cfg(any(target_os = "netbsd"))]
type type_of_udata = intptr_t;
#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
type type_of_data = i64;

#[cfg(target_os = "netbsd")]
type type_of_event_filter = u32;
#[cfg(not(target_os = "netbsd"))]
type type_of_event_filter = i16;
libc_enum! {
    #[cfg_attr(target_os = "netbsd", repr(u32))]
    #[cfg_attr(not(target_os = "netbsd"), repr(i16))]
    pub enum EventFilter {
        EVFILT_AIO,
        /// Returns whenever there is no remaining data in the write buffer
        #[cfg(target_os = "freebsd")]
        EVFILT_EMPTY,
        #[cfg(target_os = "dragonfly")]
        EVFILT_EXCEPT,
        #[cfg(any(target_os = "dragonfly",
                  target_os = "freebsd",
                  target_os = "ios",
                  target_os = "macos"))]
        EVFILT_FS,
        #[cfg(target_os = "freebsd")]
        EVFILT_LIO,
        #[cfg(any(target_os = "ios", target_os = "macos"))]
        EVFILT_MACHPORT,
        EVFILT_PROC,
        /// Returns events associated with the process referenced by a given
        /// process descriptor, created by `pdfork()`. The events to monitor are:
        ///
        /// - NOTE_EXIT: the process has exited. The exit status will be stored in data.
        #[cfg(target_os = "freebsd")]
        EVFILT_PROCDESC,
        EVFILT_READ,
        /// Returns whenever an asynchronous `sendfile()` call completes.
        #[cfg(target_os = "freebsd")]
        EVFILT_SENDFILE,
        EVFILT_SIGNAL,
        EVFILT_TIMER,
        #[cfg(any(target_os = "dragonfly",
                  target_os = "freebsd",
                  target_os = "ios",
                  target_os = "macos"))]
        EVFILT_USER,
        #[cfg(any(target_os = "ios", target_os = "macos"))]
        EVFILT_VM,
        EVFILT_VNODE,
        EVFILT_WRITE,
    }
}

#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
          target_os = "ios", target_os = "macos",
          target_os = "openbsd"))]
pub type type_of_event_flag = u16;
#[cfg(any(target_os = "netbsd"))]
pub type type_of_event_flag = u32;
libc_bitflags!{
    pub struct EventFlag: type_of_event_flag {
        EV_ADD;
        EV_CLEAR;
        EV_DELETE;
        EV_DISABLE;
        #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
                  target_os = "ios", target_os = "macos",
                  target_os = "netbsd", target_os = "openbsd"))]
        EV_DISPATCH;
        #[cfg(target_os = "freebsd")]
        EV_DROP;
        EV_ENABLE;
        EV_EOF;
        EV_ERROR;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        EV_FLAG0;
        EV_FLAG1;
        #[cfg(target_os = "dragonfly")]
        EV_NODATA;
        EV_ONESHOT;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        EV_OOBAND;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        EV_POLL;
        #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
                  target_os = "ios", target_os = "macos",
                  target_os = "netbsd", target_os = "openbsd"))]
        EV_RECEIPT;
        EV_SYSFLAGS;
    }
}

libc_bitflags!(
    pub struct FilterFlag: u32 {
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_ABSOLUTE;
        NOTE_ATTRIB;
        NOTE_CHILD;
        NOTE_DELETE;
        #[cfg(target_os = "openbsd")]
        NOTE_EOF;
        NOTE_EXEC;
        NOTE_EXIT;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
        #[allow(deprecated)]
        NOTE_EXIT_REPARENTED;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_EXITSTATUS;
        NOTE_EXTEND;
        #[cfg(any(target_os = "macos",
                  target_os = "ios",
                  target_os = "freebsd",
                  target_os = "dragonfly"))]
        NOTE_FFAND;
        #[cfg(any(target_os = "macos",
                  target_os = "ios",
                  target_os = "freebsd",
                  target_os = "dragonfly"))]
        NOTE_FFCOPY;
        #[cfg(any(target_os = "macos",
                  target_os = "ios",
                  target_os = "freebsd",
                  target_os = "dragonfly"))]
        NOTE_FFCTRLMASK;
        #[cfg(any(target_os = "macos",
                  target_os = "ios",
                  target_os = "freebsd",
                  target_os = "dragonfly"))]
        NOTE_FFLAGSMASK;
        #[cfg(any(target_os = "macos",
                  target_os = "ios",
                  target_os = "freebsd",
                  target_os = "dragonfly"))]
        NOTE_FFNOP;
        #[cfg(any(target_os = "macos",
                  target_os = "ios",
                  target_os = "freebsd",
                  target_os = "dragonfly"))]
        NOTE_FFOR;
        NOTE_FORK;
        NOTE_LINK;
        NOTE_LOWAT;
        #[cfg(target_os = "freebsd")]
        NOTE_MSECONDS;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_NONE;
        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
        NOTE_NSECONDS;
        #[cfg(target_os = "dragonfly")]
        NOTE_OOB;
        NOTE_PCTRLMASK;
        NOTE_PDATAMASK;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
        #[allow(deprecated)]
        NOTE_REAP;
        NOTE_RENAME;
        NOTE_REVOKE;
        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
        NOTE_SECONDS;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_SIGNAL;
        NOTE_TRACK;
        NOTE_TRACKERR;
        #[cfg(any(target_os = "macos",
                  target_os = "ios",
                  target_os = "freebsd",
                  target_os = "dragonfly"))]
        NOTE_TRIGGER;
        #[cfg(target_os = "openbsd")]
        NOTE_TRUNCATE;
        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
        NOTE_USECONDS;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_VM_ERROR;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_VM_PRESSURE;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_VM_PRESSURE_SUDDEN_TERMINATE;
        #[cfg(any(target_os = "macos", target_os = "ios"))]
        NOTE_VM_PRESSURE_TERMINATE;
        NOTE_WRITE;
    }
);

pub fn kqueue() -> Result<RawFd> {
    let res = unsafe { libc::kqueue() };

    Errno::result(res)
}

// KEvent can't derive Send because on some operating systems, udata is defined
// as a void*.  However, KEvent's public API always treats udata as an intptr_t,
// which is safe to Send.
unsafe impl Send for KEvent {
}

impl KEvent {
    pub fn new(ident: uintptr_t, filter: EventFilter, flags: EventFlag,
               fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent {
        KEvent { kevent: libc::kevent {
            ident,
            filter: filter as type_of_event_filter,
            flags: flags.bits(),
            fflags: fflags.bits(),
            data: data as type_of_data,
            udata: udata as type_of_udata
        } }
    }

    pub fn ident(&self) -> uintptr_t {
        self.kevent.ident
    }

    pub fn filter(&self) -> EventFilter {
        unsafe { mem::transmute(self.kevent.filter as type_of_event_filter) }
    }

    pub fn flags(&self) -> EventFlag {
        EventFlag::from_bits(self.kevent.flags).unwrap()
    }

    pub fn fflags(&self) -> FilterFlag {
        FilterFlag::from_bits(self.kevent.fflags).unwrap()
    }

    pub fn data(&self) -> intptr_t {
        self.kevent.data as intptr_t
    }

    pub fn udata(&self) -> intptr_t {
        self.kevent.udata as intptr_t
    }
}

pub fn kevent(kq: RawFd,
              changelist: &[KEvent],
              eventlist: &mut [KEvent],
              timeout_ms: usize) -> Result<usize> {

    // Convert ms to timespec
    let timeout = timespec {
        tv_sec: (timeout_ms / 1000) as time_t,
        tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long
    };

    kevent_ts(kq, changelist, eventlist, Some(timeout))
}

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "openbsd"))]
type type_of_nchanges = c_int;
#[cfg(target_os = "netbsd")]
type type_of_nchanges = size_t;

pub fn kevent_ts(kq: RawFd,
              changelist: &[KEvent],
              eventlist: &mut [KEvent],
              timeout_opt: Option<timespec>) -> Result<usize> {

    let res = unsafe {
        libc::kevent(
            kq,
            changelist.as_ptr() as *const libc::kevent,
            changelist.len() as type_of_nchanges,
            eventlist.as_mut_ptr() as *mut libc::kevent,
            eventlist.len() as type_of_nchanges,
            if let Some(ref timeout) = timeout_opt {timeout as *const timespec} else {ptr::null()})
    };

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

#[inline]
pub fn ev_set(ev: &mut KEvent,
              ident: usize,
              filter: EventFilter,
              flags: EventFlag,
              fflags: FilterFlag,
              udata: intptr_t) {

    ev.kevent.ident  = ident as uintptr_t;
    ev.kevent.filter = filter as type_of_event_filter;
    ev.kevent.flags  = flags.bits();
    ev.kevent.fflags = fflags.bits();
    ev.kevent.data   = 0;
    ev.kevent.udata  = udata as type_of_udata;
}

#[test]
fn test_struct_kevent() {
    let udata : intptr_t = 12345;

    let actual = KEvent::new(0xdead_beef,
                             EventFilter::EVFILT_READ,
                             EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
                             FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
                             0x1337,
                             udata);
    assert_eq!(0xdead_beef, actual.ident());
    assert_eq!(libc::EVFILT_READ, actual.filter() as type_of_event_filter);
    assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits());
    assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits());
    assert_eq!(0x1337, actual.data() as type_of_data);
    assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata);
    assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>());
}
<|endoftext|>


<commit_before>//! A simple wait-free, grow-only pagetable, assumes a dense keyspace.
#![allow(unsafe_code)]

use std::{
    alloc::{alloc_zeroed, Layout},
    convert::TryFrom,
    mem::{align_of, size_of},
    sync::atomic::Ordering::{Acquire, Relaxed, Release},
};

use crossbeam_epoch::{pin, Atomic, Guard, Owned, Shared};

use crate::{
    debug_delay,
    pagecache::{Page, PageView},
    Measure, M,
};

#[allow(unused)]
#[doc(hidden)]
pub const PAGETABLE_NODE_SZ: usize = size_of::<Node1>();

// Allows for around 1 trillion items to be stored
// (assuming 50% node fill, 8 items per leaf)
// and well below 1% of nodes being non-leaf nodes.
// Uses 2gb of virtual memory (almost free until used).
#[cfg(target_pointer_width = "64")]
const DESIRED_BITS: usize = 45;

// Allows for around 2 billion items to be stored
// (assuming 50% node fill, 8 items per leaf)
// and well below 1% of nodes being non-leaf nodes.
// Assumed to be enough for a 32-bit system.
#[cfg(target_pointer_width = "32")]
const DESIRED_BITS: usize = 36;

const NODE2_FAN_FACTOR: usize = 18;
const NODE1_FAN_OUT: usize = 1 << (DESIRED_BITS - NODE2_FAN_FACTOR);
const NODE2_FAN_OUT: usize = 1 << NODE2_FAN_FACTOR;
const FAN_MASK: u64 = (NODE2_FAN_OUT - 1) as u64;

pub type PageId = u64;

struct Node1 {
    children: [Atomic<Node2>; NODE1_FAN_OUT],
}

struct Node2 {
    children: [Atomic<Page>; NODE2_FAN_OUT],
}

impl Node1 {
    fn new() -> Owned<Self> {
        let size = size_of::<Self>();
        let align = align_of::<Self>();

        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);

            #[allow(clippy::cast_ptr_alignment)]
            let ptr = alloc_zeroed(layout) as *mut Self;

            Owned::from_raw(ptr)
        }
    }
}

impl Node2 {
    fn new() -> Owned<Node2> {
        let size = size_of::<Self>();
        let align = align_of::<Self>();

        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);

            #[allow(clippy::cast_ptr_alignment)]
            let ptr = alloc_zeroed(layout) as *mut Self;

            Owned::from_raw(ptr)
        }
    }
}

impl Drop for Node1 {
    fn drop(&mut self) {
        drop_iter(self.children.iter());
    }
}

impl Drop for Node2 {
    fn drop(&mut self) {
        drop_iter(self.children.iter());
    }
}

fn drop_iter<T>(iter: core::slice::Iter<'_, Atomic<T>>) {
    let guard = pin();
    for child in iter {
        let shared_child = child.load(Relaxed, &guard);
        if shared_child.is_null() {
            // this does not leak because the PageTable is
            // assumed to be dense.
            break;
        }
        unsafe {
            drop(shared_child.into_owned());
        }
    }
}

/// A simple lock-free radix tree.
pub struct PageTable {
    head: Atomic<Node1>,
}

impl Default for PageTable {
    fn default() -> Self {
        let head = Node1::new();
        Self { head: Atomic::from(head) }
    }
}

impl PageTable {
    /// # Panics
    ///
    /// will panic if the item is not null already,
    /// which represents a serious failure to
    /// properly handle lifecycles of pages in the
    /// using system.
    pub fn insert<'g>(
        &self,
        pid: PageId,
        item: Page,
        guard: &'g Guard,
    ) -> PageView<'g> {
        debug_delay();
        let tip = self.traverse(pid, guard);

        let shared = Owned::new(item).into_shared(guard);
        let old = tip.swap(shared, Release, guard);
        assert!(old.is_null());

        PageView { read: shared, entry: tip }
    }

    /// Try to get a value from the tree.
    pub fn get<'g>(
        &self,
        pid: PageId,
        guard: &'g Guard,
    ) -> Option<PageView<'g>> {
        let _measure = Measure::new(&M.get_pagetable);
        debug_delay();
        let tip = self.traverse(pid, guard);

        debug_delay();
        let res = tip.load(Acquire, guard);
        if res.is_null() {
            None
        } else {
            let page_view = PageView { read: res, entry: tip };

            Some(page_view)
        }
    }

    fn traverse<'g>(&self, k: PageId, guard: &'g Guard) -> &'g Atomic<Page> {
        let (l1k, l2k) = split_fanout(k);

        debug_delay();
        let head = self.head.load(Acquire, guard);

        debug_delay();
        let l1 = unsafe { &head.deref().children };

        debug_delay();
        let mut l2_ptr = l1[l1k].load(Acquire, guard);

        if l2_ptr.is_null() {
            let next_child = Node2::new();

            debug_delay();
            let ret = l1[l1k].compare_and_set(
                Shared::null(),
                next_child,
                Release,
                guard,
            );

            l2_ptr = match ret {
                Ok(next_child) => next_child,
                Err(returned) => {
                    drop(returned.new);
                    returned.current
                }
            };
        }

        debug_delay();
        let l2 = unsafe { &l2_ptr.deref().children };

        &l2[l2k]
    }
}

#[inline]
fn split_fanout(id: PageId) -> (usize, usize) {
    // right shift 32 on 32-bit pointer systems panics
    #[cfg(target_pointer_width = "64")]
    assert!(
        id <= 1 << DESIRED_BITS,
        "trying to access key of {}, which is \
         higher than 2 ^ {}",
        id,
        DESIRED_BITS,
    );

    let left = id >> NODE2_FAN_FACTOR;
    let right = id & FAN_MASK;

    (safe_usize(left), safe_usize(right))
}

#[inline]
fn safe_usize(value: PageId) -> usize {
    usize::try_from(value).unwrap()
}

impl Drop for PageTable {
    fn drop(&mut self) {
        let guard = pin();
        let head = self.head.load(Relaxed, &guard);
        unsafe {
            drop(head.into_owned());
        }
    }
}

#[test]
fn test_split_fanout() {
    assert_eq!(
        split_fanout(0b11_1111_1111_1111_1111),
        (0, 0b11_1111_1111_1111_1111)
    );
    assert_eq!(
        split_fanout(0b111_1111_1111_1111_1111),
        (0b1, 0b11_1111_1111_1111_1111)
    );
}
<commit_msg>Adjust PageTable max sizes to cut memory usage by a bit<commit_after>//! A simple wait-free, grow-only pagetable, assumes a dense keyspace.
#![allow(unsafe_code)]

use std::{
    alloc::{alloc_zeroed, Layout},
    convert::TryFrom,
    mem::{align_of, size_of},
    sync::atomic::Ordering::{Acquire, Relaxed, Release},
};

use crossbeam_epoch::{pin, Atomic, Guard, Owned, Shared};

use crate::{
    debug_delay,
    pagecache::{Page, PageView},
    Measure, M,
};

#[allow(unused)]
#[doc(hidden)]
pub const PAGETABLE_NODE_SZ: usize = size_of::<Node1>();

// Allows for around 1 trillion items to be stored
// 2^37 * (assuming 50% node fill, 8 items per leaf)
// and well below 1% of nodes being non-leaf nodes.
#[cfg(target_pointer_width = "64")]
const DESIRED_BITS: usize = 37;

// Allows for around 32 billion items to be stored
// 2^32 * (assuming 50% node fill of 8 items per leaf)
// and well below 1% of nodes being non-leaf nodes.
// Assumed to be enough for a 32-bit system.
#[cfg(target_pointer_width = "32")]
const DESIRED_BITS: usize = 32;

const NODE2_FAN_FACTOR: usize = 18;
const NODE1_FAN_OUT: usize = 1 << (DESIRED_BITS - NODE2_FAN_FACTOR);
const NODE2_FAN_OUT: usize = 1 << NODE2_FAN_FACTOR;
const FAN_MASK: u64 = (NODE2_FAN_OUT - 1) as u64;

pub type PageId = u64;

struct Node1 {
    children: [Atomic<Node2>; NODE1_FAN_OUT],
}

struct Node2 {
    children: [Atomic<Page>; NODE2_FAN_OUT],
}

impl Node1 {
    fn new() -> Owned<Self> {
        let size = size_of::<Self>();
        let align = align_of::<Self>();

        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);

            #[allow(clippy::cast_ptr_alignment)]
            let ptr = alloc_zeroed(layout) as *mut Self;

            Owned::from_raw(ptr)
        }
    }
}

impl Node2 {
    fn new() -> Owned<Node2> {
        let size = size_of::<Self>();
        let align = align_of::<Self>();

        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);

            #[allow(clippy::cast_ptr_alignment)]
            let ptr = alloc_zeroed(layout) as *mut Self;

            Owned::from_raw(ptr)
        }
    }
}

impl Drop for Node1 {
    fn drop(&mut self) {
        drop_iter(self.children.iter());
    }
}

impl Drop for Node2 {
    fn drop(&mut self) {
        drop_iter(self.children.iter());
    }
}

fn drop_iter<T>(iter: core::slice::Iter<'_, Atomic<T>>) {
    let guard = pin();
    for child in iter {
        let shared_child = child.load(Relaxed, &guard);
        if shared_child.is_null() {
            // this does not leak because the PageTable is
            // assumed to be dense.
            break;
        }
        unsafe {
            drop(shared_child.into_owned());
        }
    }
}

/// A simple lock-free radix tree.
pub struct PageTable {
    head: Atomic<Node1>,
}

impl Default for PageTable {
    fn default() -> Self {
        let head = Node1::new();
        Self { head: Atomic::from(head) }
    }
}

impl PageTable {
    /// # Panics
    ///
    /// will panic if the item is not null already,
    /// which represents a serious failure to
    /// properly handle lifecycles of pages in the
    /// using system.
    pub fn insert<'g>(
        &self,
        pid: PageId,
        item: Page,
        guard: &'g Guard,
    ) -> PageView<'g> {
        debug_delay();
        let tip = self.traverse(pid, guard);

        let shared = Owned::new(item).into_shared(guard);
        let old = tip.swap(shared, Release, guard);
        assert!(old.is_null());

        PageView { read: shared, entry: tip }
    }

    /// Try to get a value from the tree.
    pub fn get<'g>(
        &self,
        pid: PageId,
        guard: &'g Guard,
    ) -> Option<PageView<'g>> {
        let _measure = Measure::new(&M.get_pagetable);
        debug_delay();
        let tip = self.traverse(pid, guard);

        debug_delay();
        let res = tip.load(Acquire, guard);
        if res.is_null() {
            None
        } else {
            let page_view = PageView { read: res, entry: tip };

            Some(page_view)
        }
    }

    fn traverse<'g>(&self, k: PageId, guard: &'g Guard) -> &'g Atomic<Page> {
        let (l1k, l2k) = split_fanout(k);

        debug_delay();
        let head = self.head.load(Acquire, guard);

        debug_delay();
        let l1 = unsafe { &head.deref().children };

        debug_delay();
        let mut l2_ptr = l1[l1k].load(Acquire, guard);

        if l2_ptr.is_null() {
            let next_child = Node2::new();

            debug_delay();
            let ret = l1[l1k].compare_and_set(
                Shared::null(),
                next_child,
                Release,
                guard,
            );

            l2_ptr = match ret {
                Ok(next_child) => next_child,
                Err(returned) => {
                    drop(returned.new);
                    returned.current
                }
            };
        }

        debug_delay();
        let l2 = unsafe { &l2_ptr.deref().children };

        &l2[l2k]
    }
}

#[inline]
fn split_fanout(id: PageId) -> (usize, usize) {
    // right shift 32 on 32-bit pointer systems panics
    #[cfg(target_pointer_width = "64")]
    assert!(
        id <= 1 << DESIRED_BITS,
        "trying to access key of {}, which is \
         higher than 2 ^ {}",
        id,
        DESIRED_BITS,
    );

    let left = id >> NODE2_FAN_FACTOR;
    let right = id & FAN_MASK;

    (safe_usize(left), safe_usize(right))
}

#[inline]
fn safe_usize(value: PageId) -> usize {
    usize::try_from(value).unwrap()
}

impl Drop for PageTable {
    fn drop(&mut self) {
        let guard = pin();
        let head = self.head.load(Relaxed, &guard);
        unsafe {
            drop(head.into_owned());
        }
    }
}

#[test]
fn test_split_fanout() {
    assert_eq!(
        split_fanout(0b11_1111_1111_1111_1111),
        (0, 0b11_1111_1111_1111_1111)
    );
    assert_eq!(
        split_fanout(0b111_1111_1111_1111_1111),
        (0b1, 0b11_1111_1111_1111_1111)
    );
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::io::prelude::*;
use std::io::Cursor;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use util::{XxHash32, xxhash32};

const ENTRY_STATIC_SIZE: usize = 18; // checksum(4) + sequence(8) + key_size(2) + value_size(4)
const ENTRY_TOMBSTONE: u32 = !0;

pub type SequenceNumber = u64;

#[derive(Debug, Eq, PartialEq)]
pub struct Entry<'a> {
    pub key: Cow<'a, [u8]>,
    pub value: Cow<'a, [u8]>,
    pub sequence: SequenceNumber,
    pub deleted: bool,
}

impl<'a> Entry<'a> {
    pub fn new<K, V>(sequence: SequenceNumber, key: K, value: V) -> Entry<'a>
        where Cow<'a, [u8]>: From<K>,
              Cow<'a, [u8]>: From<V>
    {
        let v = Cow::from(value);
        assert!(v.len() < ENTRY_TOMBSTONE as usize);

        Entry {
            key: Cow::from(key),
            value: v,
            sequence: sequence,
            deleted: false,
        }
    }

    pub fn deleted<K>(sequence: SequenceNumber, key: K) -> Entry<'a>
        where Cow<'a, [u8]>: From<K>
    {
        Entry {
            key: Cow::from(key),
            value: Cow::Borrowed(&[]),
            sequence: sequence,
            deleted: true,
        }
    }

    pub fn size(&self) -> u64 {
        ENTRY_STATIC_SIZE as u64 + self.key.len() as u64 + self.value.len() as u64
    }

    pub fn to_bytes(&self) -> Vec<u8> {
        let mut cursor = Cursor::new(Vec::with_capacity(self.size() as usize));
        cursor.set_position(4);
        cursor.write_u64::<LittleEndian>(self.sequence).unwrap();
        cursor
            .write_u16::<LittleEndian>(self.key.len() as u16)
            .unwrap();

        if self.deleted {
            cursor.write_u32::<LittleEndian>(ENTRY_TOMBSTONE).unwrap();
            cursor.write_all(&self.key).unwrap();
        } else {
            cursor
                .write_u32::<LittleEndian>(self.value.len() as u32)
                .unwrap();
            cursor.write_all(&self.key).unwrap();
            cursor.write_all(&self.value).unwrap();
        }

        let checksum = xxhash32(&cursor.get_ref()[4..]);
        cursor.set_position(0);
        cursor.write_u32::<LittleEndian>(checksum).unwrap();

        cursor.into_inner()
    }

    pub fn write_bytes<W: Write>(&self, writer: &mut W) {
        let mut cursor = Cursor::new(Vec::with_capacity(ENTRY_STATIC_SIZE));
        cursor.set_position(4);
        cursor.write_u64::<LittleEndian>(self.sequence).unwrap();
        cursor
            .write_u16::<LittleEndian>(self.key.len() as u16)
            .unwrap();

        if self.deleted {
            cursor.write_u32::<LittleEndian>(ENTRY_TOMBSTONE).unwrap();
        } else {
            cursor
                .write_u32::<LittleEndian>(self.value.len() as u32)
                .unwrap();
        }

        let checksum = {
            let mut hasher = XxHash32::new();
            hasher.update(&cursor.get_ref()[4..]);
            hasher.update(&self.key);
            hasher.update(&self.value);
            hasher.get()
        };

        cursor.set_position(0);
        cursor.write_u32::<LittleEndian>(checksum).unwrap();

        writer.write_all(&cursor.into_inner()).unwrap();
        writer.write_all(&self.key).unwrap();

        if !self.deleted {
            writer.write_all(&self.value).unwrap();
        }
    }

    pub fn from_bytes(bytes: &'a [u8]) -> Entry<'a> {
        let mut cursor = Cursor::new(bytes);

        let checksum = cursor.read_u32::<LittleEndian>().unwrap();
        assert_eq!(xxhash32(&bytes[4..]), checksum);

        let sequence = cursor.read_u64::<LittleEndian>().unwrap();
        let key_size = cursor.read_u16::<LittleEndian>().unwrap();
        let value_size = cursor.read_u32::<LittleEndian>().unwrap();

        let deleted = value_size == ENTRY_TOMBSTONE;

        let value = if deleted {
            let empty: &[u8] = &[];
            Cow::from(empty)
        } else {
            Cow::from(&bytes[ENTRY_STATIC_SIZE + key_size as usize..])
        };

        Entry {
            key: Cow::from(&bytes[ENTRY_STATIC_SIZE..ENTRY_STATIC_SIZE + key_size as usize]),
            value: value,
            sequence: sequence,
            deleted: value_size == ENTRY_TOMBSTONE,
        }
    }

    pub fn from_read<R: Read>(reader: &mut R) -> Entry<'a> {
        let mut header = vec![0u8; ENTRY_STATIC_SIZE as usize];
        reader.read(&mut header).unwrap();

        let mut cursor = Cursor::new(header);
        let checksum = cursor.read_u32::<LittleEndian>().unwrap();
        let sequence = cursor.read_u64::<LittleEndian>().unwrap();
        let key_size = cursor.read_u16::<LittleEndian>().unwrap();
        let value_size = cursor.read_u32::<LittleEndian>().unwrap();

        let mut key = vec![0u8; key_size as usize];
        reader.read_exact(&mut key).unwrap();

        let deleted = value_size == ENTRY_TOMBSTONE;

        let value = if deleted {
            let empty: &[u8] = &[];
            Cow::from(empty)
        } else {
            let mut value = vec![0u8; value_size as usize];
            reader.read_exact(&mut value).unwrap();
            Cow::from(value)
        };

        let hash = {
            let mut hasher = XxHash32::new();
            hasher.update(&cursor.get_ref()[4..]);
            hasher.update(&key);
            hasher.update(&value);
            hasher.get()
        };

        assert_eq!(hash, checksum);

        Entry {
            key: Cow::from(key),
            value: value,
            sequence: sequence,
            deleted: deleted,
        }
    }
}

pub struct Hint<'a> {
    pub key: Cow<'a, [u8]>,
    pub entry_pos: u64,
    pub value_size: u32,
    pub sequence: SequenceNumber,
    pub deleted: bool,
}

impl<'a> Hint<'a> {
    pub fn new(e: &'a Entry, entry_pos: u64) -> Hint<'a> {
        Hint {
            key: Cow::from(&*e.key),
            entry_pos: entry_pos,
            value_size: e.value.len() as u32,
            sequence: e.sequence,
            deleted: e.deleted,
        }
    }

    pub fn from(e: Entry<'a>, entry_pos: u64) -> Hint<'a> {
        Hint {
            key: e.key,
            entry_pos: entry_pos,
            value_size: e.value.len() as u32,
            sequence: e.sequence,
            deleted: e.deleted,
        }
    }

    pub fn entry_size(&self) -> u64 {
        ENTRY_STATIC_SIZE as u64 + self.key.len() as u64 + self.value_size as u64
    }

    pub fn write_bytes<W: Write>(&self, writer: &mut W) {
        writer.write_u64::<LittleEndian>(self.sequence).unwrap();
        writer
            .write_u16::<LittleEndian>(self.key.len() as u16)
            .unwrap();

        if self.deleted {
            writer.write_u32::<LittleEndian>(ENTRY_TOMBSTONE).unwrap();
        } else {
            writer.write_u32::<LittleEndian>(self.value_size).unwrap();
        }

        writer.write_u64::<LittleEndian>(self.entry_pos).unwrap();
        writer.write(&self.key).unwrap();
    }

    pub fn from_read<R: Read>(reader: &mut R) -> Hint<'a> {
        let sequence = reader.read_u64::<LittleEndian>().unwrap();
        let key_size = reader.read_u16::<LittleEndian>().unwrap();
        let value_size = reader.read_u32::<LittleEndian>().unwrap();
        let entry_pos = reader.read_u64::<LittleEndian>().unwrap();

        let mut key = vec![0u8; key_size as usize];
        reader.read_exact(&mut key).unwrap();

        let deleted = value_size == ENTRY_TOMBSTONE;

        Hint {
            key: Cow::from(key),
            entry_pos: entry_pos,
            value_size: if deleted { 0 } else { value_size },
            sequence: sequence,
            deleted: value_size == ENTRY_TOMBSTONE,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use data::Entry;

    #[test]
    fn test_serialization() {
        let sequence = 0;
        let key: &[u8] = &[0, 0, 0];
        let value: &[u8] = &[0, 0, 0];
        let entry = Entry::new(sequence, key, value);
        let deleted_entry = Entry::deleted(sequence, key);

        assert_eq!(entry.to_bytes().len(), 24);

        assert_eq!(entry, Entry::from_bytes(&entry.to_bytes()));
        assert_eq!(entry, Entry::from_read(&mut Cursor::new(entry.to_bytes())));
        let mut v = Vec::new();
        entry.write_bytes(&mut v);
        assert_eq!(entry, Entry::from_bytes(&v));

        assert_eq!(deleted_entry, Entry::from_bytes(&deleted_entry.to_bytes()));
        assert_eq!(deleted_entry,
                   Entry::from_read(&mut Cursor::new(deleted_entry.to_bytes())));
        v.clear();
        deleted_entry.write_bytes(&mut v);
        assert_eq!(deleted_entry, Entry::from_bytes(&v));
    }

    #[test]
    fn test_deleted() {
        let sequence = 0;
        let key: &[u8] = &[0, 0, 0];

        assert!(Entry::deleted(sequence, key).deleted);
        assert_eq!(Entry::deleted(sequence, key).value.len(), 0);
    }
}
<commit_msg>fix clippy errors<commit_after>use std::borrow::Cow;
use std::io::prelude::*;
use std::io::Cursor;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use util::{XxHash32, xxhash32};

const ENTRY_STATIC_SIZE: usize = 18; // checksum(4) + sequence(8) + key_size(2) + value_size(4)
const ENTRY_TOMBSTONE: u32 = !0;

pub type SequenceNumber = u64;

#[derive(Debug, Eq, PartialEq)]
pub struct Entry<'a> {
    pub key: Cow<'a, [u8]>,
    pub value: Cow<'a, [u8]>,
    pub sequence: SequenceNumber,
    pub deleted: bool,
}

impl<'a> Entry<'a> {
    pub fn new<K, V>(sequence: SequenceNumber, key: K, value: V) -> Entry<'a>
        where Cow<'a, [u8]>: From<K>,
              Cow<'a, [u8]>: From<V>
    {
        let v = Cow::from(value);
        assert!(v.len() < ENTRY_TOMBSTONE as usize);

        Entry {
            key: Cow::from(key),
            value: v,
            sequence: sequence,
            deleted: false,
        }
    }

    pub fn deleted<K>(sequence: SequenceNumber, key: K) -> Entry<'a>
        where Cow<'a, [u8]>: From<K>
    {
        Entry {
            key: Cow::from(key),
            value: Cow::Borrowed(&[]),
            sequence: sequence,
            deleted: true,
        }
    }

    pub fn size(&self) -> u64 {
        ENTRY_STATIC_SIZE as u64 + self.key.len() as u64 + self.value.len() as u64
    }

    pub fn to_bytes(&self) -> Vec<u8> {
        let mut cursor = Cursor::new(Vec::with_capacity(self.size() as usize));
        cursor.set_position(4);
        cursor.write_u64::<LittleEndian>(self.sequence).unwrap();
        cursor
            .write_u16::<LittleEndian>(self.key.len() as u16)
            .unwrap();

        if self.deleted {
            cursor.write_u32::<LittleEndian>(ENTRY_TOMBSTONE).unwrap();
            cursor.write_all(&self.key).unwrap();
        } else {
            cursor
                .write_u32::<LittleEndian>(self.value.len() as u32)
                .unwrap();
            cursor.write_all(&self.key).unwrap();
            cursor.write_all(&self.value).unwrap();
        }

        let checksum = xxhash32(&cursor.get_ref()[4..]);
        cursor.set_position(0);
        cursor.write_u32::<LittleEndian>(checksum).unwrap();

        cursor.into_inner()
    }

    pub fn write_bytes<W: Write>(&self, writer: &mut W) {
        let mut cursor = Cursor::new(Vec::with_capacity(ENTRY_STATIC_SIZE));
        cursor.set_position(4);
        cursor.write_u64::<LittleEndian>(self.sequence).unwrap();
        cursor
            .write_u16::<LittleEndian>(self.key.len() as u16)
            .unwrap();

        if self.deleted {
            cursor.write_u32::<LittleEndian>(ENTRY_TOMBSTONE).unwrap();
        } else {
            cursor
                .write_u32::<LittleEndian>(self.value.len() as u32)
                .unwrap();
        }

        let checksum = {
            let mut hasher = XxHash32::new();
            hasher.update(&cursor.get_ref()[4..]);
            hasher.update(&self.key);
            hasher.update(&self.value);
            hasher.get()
        };

        cursor.set_position(0);
        cursor.write_u32::<LittleEndian>(checksum).unwrap();

        writer.write_all(&cursor.into_inner()).unwrap();
        writer.write_all(&self.key).unwrap();

        if !self.deleted {
            writer.write_all(&self.value).unwrap();
        }
    }

    pub fn from_bytes(bytes: &'a [u8]) -> Entry<'a> {
        let mut cursor = Cursor::new(bytes);

        let checksum = cursor.read_u32::<LittleEndian>().unwrap();
        assert_eq!(xxhash32(&bytes[4..]), checksum);

        let sequence = cursor.read_u64::<LittleEndian>().unwrap();
        let key_size = cursor.read_u16::<LittleEndian>().unwrap();
        let value_size = cursor.read_u32::<LittleEndian>().unwrap();

        let deleted = value_size == ENTRY_TOMBSTONE;

        let value = if deleted {
            let empty: &[u8] = &[];
            Cow::from(empty)
        } else {
            Cow::from(&bytes[ENTRY_STATIC_SIZE + key_size as usize..])
        };

        Entry {
            key: Cow::from(&bytes[ENTRY_STATIC_SIZE..ENTRY_STATIC_SIZE + key_size as usize]),
            value: value,
            sequence: sequence,
            deleted: value_size == ENTRY_TOMBSTONE,
        }
    }

    pub fn from_read<R: Read>(reader: &mut R) -> Entry<'a> {
        let mut header = vec![0u8; ENTRY_STATIC_SIZE as usize];
        reader.read_exact(&mut header).unwrap();

        let mut cursor = Cursor::new(header);
        let checksum = cursor.read_u32::<LittleEndian>().unwrap();
        let sequence = cursor.read_u64::<LittleEndian>().unwrap();
        let key_size = cursor.read_u16::<LittleEndian>().unwrap();
        let value_size = cursor.read_u32::<LittleEndian>().unwrap();

        let mut key = vec![0u8; key_size as usize];
        reader.read_exact(&mut key).unwrap();

        let deleted = value_size == ENTRY_TOMBSTONE;

        let value = if deleted {
            let empty: &[u8] = &[];
            Cow::from(empty)
        } else {
            let mut value = vec![0u8; value_size as usize];
            reader.read_exact(&mut value).unwrap();
            Cow::from(value)
        };

        let hash = {
            let mut hasher = XxHash32::new();
            hasher.update(&cursor.get_ref()[4..]);
            hasher.update(&key);
            hasher.update(&value);
            hasher.get()
        };

        assert_eq!(hash, checksum);

        Entry {
            key: Cow::from(key),
            value: value,
            sequence: sequence,
            deleted: deleted,
        }
    }
}

pub struct Hint<'a> {
    pub key: Cow<'a, [u8]>,
    pub entry_pos: u64,
    pub value_size: u32,
    pub sequence: SequenceNumber,
    pub deleted: bool,
}

impl<'a> Hint<'a> {
    pub fn new(e: &'a Entry, entry_pos: u64) -> Hint<'a> {
        Hint {
            key: Cow::from(&*e.key),
            entry_pos: entry_pos,
            value_size: e.value.len() as u32,
            sequence: e.sequence,
            deleted: e.deleted,
        }
    }

    pub fn from(e: Entry<'a>, entry_pos: u64) -> Hint<'a> {
        Hint {
            key: e.key,
            entry_pos: entry_pos,
            value_size: e.value.len() as u32,
            sequence: e.sequence,
            deleted: e.deleted,
        }
    }

    pub fn entry_size(&self) -> u64 {
        ENTRY_STATIC_SIZE as u64 + self.key.len() as u64 + self.value_size as u64
    }

    pub fn write_bytes<W: Write>(&self, writer: &mut W) {
        writer.write_u64::<LittleEndian>(self.sequence).unwrap();
        writer
            .write_u16::<LittleEndian>(self.key.len() as u16)
            .unwrap();

        if self.deleted {
            writer.write_u32::<LittleEndian>(ENTRY_TOMBSTONE).unwrap();
        } else {
            writer.write_u32::<LittleEndian>(self.value_size).unwrap();
        }

        writer.write_u64::<LittleEndian>(self.entry_pos).unwrap();
        writer.write_all(&self.key).unwrap();
    }

    pub fn from_read<R: Read>(reader: &mut R) -> Hint<'a> {
        let sequence = reader.read_u64::<LittleEndian>().unwrap();
        let key_size = reader.read_u16::<LittleEndian>().unwrap();
        let value_size = reader.read_u32::<LittleEndian>().unwrap();
        let entry_pos = reader.read_u64::<LittleEndian>().unwrap();

        let mut key = vec![0u8; key_size as usize];
        reader.read_exact(&mut key).unwrap();

        let deleted = value_size == ENTRY_TOMBSTONE;

        Hint {
            key: Cow::from(key),
            entry_pos: entry_pos,
            value_size: if deleted { 0 } else { value_size },
            sequence: sequence,
            deleted: value_size == ENTRY_TOMBSTONE,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use data::Entry;

    #[test]
    fn test_serialization() {
        let sequence = 0;
        let key: &[u8] = &[0, 0, 0];
        let value: &[u8] = &[0, 0, 0];
        let entry = Entry::new(sequence, key, value);
        let deleted_entry = Entry::deleted(sequence, key);

        assert_eq!(entry.to_bytes().len(), 24);

        assert_eq!(entry, Entry::from_bytes(&entry.to_bytes()));
        assert_eq!(entry, Entry::from_read(&mut Cursor::new(entry.to_bytes())));
        let mut v = Vec::new();
        entry.write_bytes(&mut v);
        assert_eq!(entry, Entry::from_bytes(&v));

        assert_eq!(deleted_entry, Entry::from_bytes(&deleted_entry.to_bytes()));
        assert_eq!(deleted_entry,
                   Entry::from_read(&mut Cursor::new(deleted_entry.to_bytes())));
        v.clear();
        deleted_entry.write_bytes(&mut v);
        assert_eq!(deleted_entry, Entry::from_bytes(&v));
    }

    #[test]
    fn test_deleted() {
        let sequence = 0;
        let key: &[u8] = &[0, 0, 0];

        assert!(Entry::deleted(sequence, key).deleted);
        assert_eq!(Entry::deleted(sequence, key).value.len(), 0);
    }
}
<|endoftext|>


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

use helpers::HelperDef;
use registry::Registry;
use context::{Context, JsonTruthy, to_json};
use render::{Renderable, RenderContext, RenderError, Helper};

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

impl HelperDef for WithHelper {
    fn call(&self,
            c: &Context,
            h: &Helper,
            r: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let param = try!(h.param(0)
                          .ok_or_else(|| RenderError::new("Param not found for helper \"with\"")));

        rc.promote_local_vars();

        let result = {
            let mut local_rc = rc.derive();

            let not_empty = param.value().is_truthy();
            let template = if not_empty {
                h.template()
            } else {
                h.inverse()
            };

            if let Some(path_root) = param.path_root() {
                let local_path_root = format!("{}/{}", local_rc.get_path(), path_root);
                local_rc.push_local_path_root(local_path_root);
            }
            if not_empty {
                if let Some(inner_path) = param.path() {
                    let new_path = format!("{}/{}", local_rc.get_path(), inner_path);
                    local_rc.set_path(new_path);
                }

                if let Some(block_param) = h.block_param() {
                    let mut map = BTreeMap::new();
                    map.insert(block_param.to_string(), to_json(param.value()));
                    local_rc.push_block_context(&map);
                }
            }

            let result = match template {
                Some(t) => t.render(c, r, &mut local_rc),
                None => Ok(()),
            };

            if h.block_param().is_some() {
                local_rc.pop_block_context();
            }

            if param.path_root().is_some() {
                local_rc.pop_local_path_root();
            }

            result
        };

        rc.demote_local_vars();
        result
    }
}

pub static WITH_HELPER: WithHelper = WithHelper;

#[cfg(test)]
#[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
mod test {
    use template::Template;
    use registry::Registry;

    use std::collections::BTreeMap;
    use serialize::json::{Json, ToJson};

    struct Address {
        city: String,
        country: String,
    }

    impl ToJson for Address {
        fn to_json(&self) -> Json {
            let mut m = BTreeMap::new();
            m.insert("city".to_string(), self.city.to_json());
            m.insert("country".to_string(), self.country.to_json());
            Json::Object(m)
        }
    }

    struct Person {
        name: String,
        age: i16,
        addr: Address,
        titles: Vec<String>,
    }

    impl ToJson for Person {
        fn to_json(&self) -> Json {
            let mut m = BTreeMap::new();
            m.insert("name".to_string(), self.name.to_json());
            m.insert("age".to_string(), self.age.to_json());
            m.insert("addr".to_string(), self.addr.to_json());
            m.insert("titles".to_string(), self.titles.to_json());
            Json::Object(m)
        }
    }

    #[test]
    fn test_with() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let t0 = Template::compile("{{#with addr}}{{city}}{{/with}}".to_string()).ok().unwrap();
        let t1 = Template::compile("{{#with notfound}}hello{{else}}world{{/with}}".to_string())
                     .ok()
                     .unwrap();
        let t2 = Template::compile("{{#with addr/country}}{{this}}{{/with}}".to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);
        handlebars.register_template("t2", t2);

        let r0 = handlebars.render("t0", &person);
        assert_eq!(r0.ok().unwrap(), "Beijing".to_string());

        let r1 = handlebars.render("t1", &person);
        assert_eq!(r1.ok().unwrap(), "world".to_string());

        let r2 = handlebars.render("t2", &person);
        assert_eq!(r2.ok().unwrap(), "China".to_string());
    }

    #[test]
    fn test_with_block_param() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let t0 = Template::compile("{{#with addr as |a|}}{{a.city}}{{/with}}".to_string())
                     .ok()
                     .unwrap();
        let t1 = Template::compile("{{#with notfound as |c|}}hello{{else}}world{{/with}}"
                                       .to_string())
                     .ok()
                     .unwrap();
        let t2 = Template::compile("{{#with addr/country as |t|}}{{t}}{{/with}}".to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);
        handlebars.register_template("t2", t2);

        let r0 = handlebars.render("t0", &person);
        assert_eq!(r0.ok().unwrap(), "Beijing".to_string());

        let r1 = handlebars.render("t1", &person);
        assert_eq!(r1.ok().unwrap(), "world".to_string());

        let r2 = handlebars.render("t2", &person);
        assert_eq!(r2.ok().unwrap(), "China".to_string());
    }

    #[test]
    fn test_with_in_each() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let addr2 = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person2 = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr2,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let people = vec![person, person2];

        let t0 = Template::compile("{{#each this}}{{#with addr}}{{city}}{{/with}}{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();
        let t1 = Template::compile("{{#each this}}{{#with addr}}{{../age}}{{/with}}{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();
        let t2 = Template::compile("{{#each this}}{{#with addr}}{{@../index}}{{/with}}{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);
        handlebars.register_template("t2", t2);

        let r0 = handlebars.render("t0", &people);
        assert_eq!(r0.ok().unwrap(), "BeijingBeijing".to_string());

        let r1 = handlebars.render("t1", &people);
        assert_eq!(r1.ok().unwrap(), "2727".to_string());

        let r2 = handlebars.render("t2", &people);
        assert_eq!(r2.ok().unwrap(), "01".to_string());
    }
}
<commit_msg>(test) added test for path up with<commit_after>use std::collections::BTreeMap;

use helpers::HelperDef;
use registry::Registry;
use context::{Context, JsonTruthy, to_json};
use render::{Renderable, RenderContext, RenderError, Helper};

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

impl HelperDef for WithHelper {
    fn call(&self,
            c: &Context,
            h: &Helper,
            r: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let param = try!(h.param(0)
                          .ok_or_else(|| RenderError::new("Param not found for helper \"with\"")));

        rc.promote_local_vars();

        let result = {
            let mut local_rc = rc.derive();

            let not_empty = param.value().is_truthy();
            let template = if not_empty {
                h.template()
            } else {
                h.inverse()
            };

            if let Some(path_root) = param.path_root() {
                let local_path_root = format!("{}/{}", local_rc.get_path(), path_root);
                local_rc.push_local_path_root(local_path_root);
            }
            if not_empty {
                if let Some(inner_path) = param.path() {
                    let new_path = format!("{}/{}", local_rc.get_path(), inner_path);
                    local_rc.set_path(new_path);
                }

                if let Some(block_param) = h.block_param() {
                    let mut map = BTreeMap::new();
                    map.insert(block_param.to_string(), to_json(param.value()));
                    local_rc.push_block_context(&map);
                }
            }

            let result = match template {
                Some(t) => t.render(c, r, &mut local_rc),
                None => Ok(()),
            };

            if h.block_param().is_some() {
                local_rc.pop_block_context();
            }

            if param.path_root().is_some() {
                local_rc.pop_local_path_root();
            }

            result
        };

        rc.demote_local_vars();
        result
    }
}

pub static WITH_HELPER: WithHelper = WithHelper;

#[cfg(test)]
#[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
mod test {
    use template::Template;
    use registry::Registry;
    use context::to_json;

    use std::collections::BTreeMap;
    use serialize::json::{Json, ToJson};

    struct Address {
        city: String,
        country: String,
    }

    impl ToJson for Address {
        fn to_json(&self) -> Json {
            let mut m = BTreeMap::new();
            m.insert("city".to_string(), self.city.to_json());
            m.insert("country".to_string(), self.country.to_json());
            Json::Object(m)
        }
    }

    struct Person {
        name: String,
        age: i16,
        addr: Address,
        titles: Vec<String>,
    }

    impl ToJson for Person {
        fn to_json(&self) -> Json {
            let mut m = BTreeMap::new();
            m.insert("name".to_string(), self.name.to_json());
            m.insert("age".to_string(), self.age.to_json());
            m.insert("addr".to_string(), self.addr.to_json());
            m.insert("titles".to_string(), self.titles.to_json());
            Json::Object(m)
        }
    }

    #[test]
    fn test_with() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let t0 = Template::compile("{{#with addr}}{{city}}{{/with}}".to_string()).ok().unwrap();
        let t1 = Template::compile("{{#with notfound}}hello{{else}}world{{/with}}".to_string())
                     .ok()
                     .unwrap();
        let t2 = Template::compile("{{#with addr/country}}{{this}}{{/with}}".to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);
        handlebars.register_template("t2", t2);

        let r0 = handlebars.render("t0", &person);
        assert_eq!(r0.ok().unwrap(), "Beijing".to_string());

        let r1 = handlebars.render("t1", &person);
        assert_eq!(r1.ok().unwrap(), "world".to_string());

        let r2 = handlebars.render("t2", &person);
        assert_eq!(r2.ok().unwrap(), "China".to_string());
    }

    #[test]
    fn test_with_block_param() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let t0 = Template::compile("{{#with addr as |a|}}{{a.city}}{{/with}}".to_string())
                     .ok()
                     .unwrap();
        let t1 = Template::compile("{{#with notfound as |c|}}hello{{else}}world{{/with}}"
                                       .to_string())
                     .ok()
                     .unwrap();
        let t2 = Template::compile("{{#with addr/country as |t|}}{{t}}{{/with}}".to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);
        handlebars.register_template("t2", t2);

        let r0 = handlebars.render("t0", &person);
        assert_eq!(r0.ok().unwrap(), "Beijing".to_string());

        let r1 = handlebars.render("t1", &person);
        assert_eq!(r1.ok().unwrap(), "world".to_string());

        let r2 = handlebars.render("t2", &person);
        assert_eq!(r2.ok().unwrap(), "China".to_string());
    }

    #[test]
    fn test_with_in_each() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let addr2 = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person2 = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr2,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let people = vec![person, person2];

        let t0 = Template::compile("{{#each this}}{{#with addr}}{{city}}{{/with}}{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();
        let t1 = Template::compile("{{#each this}}{{#with addr}}{{../age}}{{/with}}{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();
        let t2 = Template::compile("{{#each this}}{{#with addr}}{{@../index}}{{/with}}{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);
        handlebars.register_template("t2", t2);

        let r0 = handlebars.render("t0", &people);
        assert_eq!(r0.ok().unwrap(), "BeijingBeijing".to_string());

        let r1 = handlebars.render("t1", &people);
        assert_eq!(r1.ok().unwrap(), "2727".to_string());

        let r2 = handlebars.render("t2", &people);
        assert_eq!(r2.ok().unwrap(), "01".to_string());
    }

    #[test]
    fn test_path_up() {
        let t0 = Template::compile("{{#with a}}{{#with b}}{{../../d}}{{/with}}{{/with}}"
                                       .to_string())
                     .ok()
                     .unwrap();
        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let data = btreemap! {
            "a".to_string() => to_json(&btreemap! {
                "b".to_string() => vec![btreemap!{"c".to_string() => vec![1]}]
            }),
            "d".to_string() => to_json(&1)
        };

        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.ok().unwrap(), "1".to_string());

    }
}
<|endoftext|>


<commit_before>/// generates images used to test NMF

use std::ops::{Index, IndexMut, Mul, Add, Div};

use std;

use std::cmp::PartialOrd;

use std::ops::Range;
use std::iter::{Map, Rev, once, Once, Chain, Zip};

extern crate num;
use num::traits::{Zero, One, FromPrimitive, ToPrimitive, Float};

extern crate nalgebra;
use nalgebra::{DMat, DVec, Norm, BaseFloat};

extern crate image;
use self::image::{ImageBuffer, Luma, DynamicImage};

use partialmax::PartialMaxIteratorExt;

quick_error! {
    #[derive(Debug)]
    pub enum ImageSaveError {
        /// an error has occured when opening the file
        Io(err: std::io::Error) {}
        /// an error has occured when writing the image into the file
        Image(err: image::ImageError) {}
    }
}

pub type HorizontalReturnT<T> = Map<Range<usize>, fn(usize) -> T>;
pub type VerticalReturnT<T> = Map<Rev<Range<usize>>, fn(usize) -> T>;
pub type StaticReturnT<T> = Chain<Chain<Chain<Once<T>, VerticalReturnT<T>>, Once<T>>, HorizontalReturnT<T>>;
pub type TestReturnT<T> = Map<Zip<HorizontalReturnT<T>, VerticalReturnT<T>>, fn((T, T)) -> T>;

// TODO move the type constraints back up here
// TODO split into multiple traits
// normalize
// images
// creation
pub trait Testimage<T> {
    type Item;

    /// returns a testimage that has `1` in `row` for all `cols` and `0` everywhere else
    ///
    /// ```
    /// Testimage::new_horizontal_line(9, 0..5);
    /// ```
    fn new_horizontal_line<I: Iterator<Item = usize>>(row: usize, cols: I) -> Self where Self::Item: Clone + Copy + Zero + One;
    /// returns a testimage that has `1` in `col` for all `rows` and `0` everywhere else
    ///
    /// ```
    /// Testimage::new_vertical_line(5..10, 0);
    /// ```
    fn new_vertical_line<I: Iterator<Item = usize>>(rows: I, col: usize) -> Self where Self::Item: Clone + Copy + Zero + One;
    /// # Panics
    /// panics unless all the values in `self` are between
    /// `0` (inclusive) and `1` (inclusive)
    fn luma01_to_image(&self) -> DynamicImage where Self::Item: Zero + One + FromPrimitive + ToPrimitive + PartialOrd + Float;
    /// # Panics
    /// panics unless all the values in `self` are between
    /// `0` (inclusive) and `1` (inclusive)
    fn save_luma01_to_png(&self, filename: &str) -> Result<(), ImageSaveError> where Self::Item: Zero + One + FromPrimitive + ToPrimitive + PartialOrd + Float;
    fn static_factors() -> StaticReturnT<Self>
        where Self: Sized,
              Self::Item: Clone + Copy + Zero + One;
    // TODO it's probably a much better idea to just use plain functions here
    fn horizontal_evolving_factors() -> HorizontalReturnT<Self> where Self::Item: Clone + Copy + Zero + One;
    fn vertical_evolving_factors() -> VerticalReturnT<Self> where Self::Item: Clone + Copy + Zero + One;
    // TODO trait
    fn linear_combination<C>(factors: &[Self], coefficients: &[C]) -> Self
        where C: Clone,
              Self: Sized + Mul<C, Output = Self>,
              Self::Item: Clone + Copy + Zero;
    fn normalize_mut(self) -> Self
        where Self::Item: Clone + Copy + BaseFloat,
              Self: Div<T, Output = Self>,
              Self: Sized;
    fn testimages() -> TestReturnT<Self> where Self::Item: Clone + Copy + Zero + One + BaseFloat;
}

impl<T> Testimage<T> for DMat<T> {
    // here's where we associate Self::Item and T
    type Item = T;

    fn new_horizontal_line<I: Iterator<Item = usize>>(row: usize, cols: I) -> Self
        where Self::Item: Clone + Copy + Zero + One
    {
        let mut factor: DMat<Self::Item> = DMat::new_zeros(10, 10);
        for col in cols {
            *factor.index_mut((row, col)) = Self::Item::one();
        }
        factor
    }

    fn new_vertical_line<I: Iterator<Item = usize>>(rows: I, col: usize) -> Self
        where Self::Item: Clone + Copy + Zero + One
    {
        let mut factor: DMat<Self::Item> = DMat::new_zeros(10, 10);
        for row in rows {
            *factor.index_mut((row, col)) = Self::Item::one();
        }
        factor
    }

    fn luma01_to_image(&self) -> DynamicImage
        where Self::Item: Zero + One + FromPrimitive + ToPrimitive + PartialOrd + Float
    {
        let mut image_buffer = ImageBuffer::new(self.ncols() as u32, self.nrows() as u32);
        for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
            let value = self.index((y as usize, x as usize));
            assert!(Self::Item::zero() <= *value);
            assert!(*value <= Self::Item::one());
            let max = Self::Item::from_u8(std::u8::MAX).unwrap();
            let byte = (*value * max).round().to_u8().unwrap();
            *pixel = Luma([byte]);
        }
        DynamicImage::ImageLuma8(image_buffer)
    }

    fn save_luma01_to_png(&self, filename: &str) -> Result<(), ImageSaveError>
        where Self::Item: Zero + One + FromPrimitive + ToPrimitive + PartialOrd + Float
    {
        let image = self.luma01_to_image();
        let path = std::path::Path::new(filename);
        let mut file = try!(std::fs::File::create(&path).map_err(ImageSaveError::Io));
        image.save(&mut file, image::PNG).map_err(ImageSaveError::Image)
    }

    fn static_factors() -> StaticReturnT<Self>
        where Self::Item: Clone + Copy + Zero + One
    {
        fn helper_horizontal<U: Clone + Copy + Zero + One>(row: usize) -> DMat<U> {
            Testimage::new_horizontal_line(row, 0..10)
        }
        fn helper_vertical<U: Clone + Copy + Zero + One>(col: usize) -> DMat<U> {
            Testimage::new_vertical_line(0..10, col)
        }
        once(Testimage::new_horizontal_line(9, 0..5))
            .chain((0..9).rev().map(helper_horizontal as fn(usize) -> Self))
            .chain(once(Testimage::new_vertical_line(5..10, 0)))
            .chain((1..10).map(helper_vertical as fn(usize) -> Self))
    }

    fn horizontal_evolving_factors() -> HorizontalReturnT<Self>
        where Self::Item: Clone + Copy + Zero + One
    {
        fn helper<U: Clone + Copy + Zero + One>(start_col: usize) -> DMat<U> {
            Testimage::new_horizontal_line(9, start_col..(start_col + 5))
        }
        (0..6).map(helper)
    }

    fn vertical_evolving_factors() -> VerticalReturnT<Self>
        where Self::Item: Clone + Copy + Zero + One
    {
        fn helper<U: Clone + Copy + Zero + One>(start_row: usize) -> DMat<U> {
            Testimage::new_vertical_line(start_row..(start_row + 5), 0)
        }
        (0..6).rev().map(helper)
    }

    fn linear_combination<C>(factors: &[Self], coefficients: &[C]) -> Self
        where C: Clone,
              Self: Mul<C, Output = Self>,
              Self::Item: Clone + Copy + Zero
    {
        assert!(0 < factors.len());
        assert_eq!(factors.len(), coefficients.len());
        let nrows = factors[0].nrows();
        let ncols = factors[0].ncols();
        let mut result = DMat::new_zeros(nrows, ncols);
        for (factor, coefficient) in factors.iter().zip(coefficients.iter()) {
            assert_eq!(factor.nrows(), nrows);
            assert_eq!(factor.ncols(), ncols);
            result = result.add(factor.clone().mul(coefficient.clone()));
        }
        result
    }

    /// divide all values by max value
    // TODO put this into its own trait
    fn normalize_mut(self) -> Self
        where Self::Item: Clone + Copy + PartialOrd,
              Self: Div<T, Output = Self>,
              Self: Sized
    {
        let max = self.as_vec().iter().cloned().partial_max().unwrap();
        self.div(max)
    }

    fn testimages() -> TestReturnT<Self>
        where Self::Item: Clone + Copy + Zero + One + BaseFloat
    {
        fn helper<U, V, W, X>((a, b): (U, V)) -> W
            where U: Add<V, Output=W>,
                  W: Testimage<X>,
                  W::Item: Clone + BaseFloat,
                  W: Div<X, Output=W>
        {
            a.add(b).normalize_mut()
        }
        Testimage::horizontal_evolving_factors()
            .zip(Testimage::vertical_evolving_factors())
            .map(helper)

        //     horizontal
        //     .zip(vertical)
        //     .enumerate()
        //     .map(|(step, (horizontal, vertical))| {
        //         // let h: Self = horizontal;
        //         // // let cloned: Self = (*horizontal).clone::<Self>();
        //         // let foo = h.add(vertical);
        //         // let result: Self = foo.normalize::<Self>();
        //         // result
        //         horizontal.clone()
        //     }))
    }
}

// fn random_coefficient<R: Rng>(rng: &mut R) -> FloatType {
//     let Closed01(random) = rng.gen::<Closed01<FloatType>>();
//     random
// }
//
// fn random_coefficients<R: Rng>(rng: &mut R, count: usize) -> DVec<FloatType> {
//     let mut coefficients: DVec<FloatType> = DVec::new_zeros(count);
//     for i in 0..count {
//         coefficients[i] = random_coefficient(rng);
//     }
//     coefficients
// }
<commit_msg>remove src/testimage.rs<commit_after><|endoftext|>


<commit_before>/// generates images used to test NMF

use std::ops::{Index, IndexMut, Mul, Add};

use std;

use std::cmp::PartialOrd;

use std::ops::Range;
use std::iter::{Map, Rev, once, Once, Chain, Zip};

extern crate num;
use num::traits::{Zero, One, FromPrimitive, ToPrimitive, Float};

extern crate nalgebra;
use nalgebra::{DMat, DVec, Norm, BaseFloat};

extern crate image;
use self::image::{ImageBuffer, Luma, DynamicImage};

quick_error! {
    #[derive(Debug)]
    pub enum ImageSaveError {
        /// an error has occured when opening the file
        Io(err: std::io::Error) {}
        /// an error has occured when writing the image into the file
        Image(err: image::ImageError) {}
    }
}

pub type Horizontal<T> = Map<Range<usize>, fn(usize) -> T>;
pub type Vertical<T> = Map<Rev<Range<usize>>, fn(usize) -> T>;
pub type Static<T> = Chain<Chain<Chain<Once<T>, Vertical<T>>, Once<T>>, Horizontal<T>>;
pub type Test<T> = Map<Zip<Horizontal<T>, Vertical<T>>, fn((T, T)) -> T>;

// TODO move the type constraints back up here
pub trait Testimage {
    type Item;

    /// returns a testimage that has `1` in `row` for all `cols` and `0` everywhere else
    ///
    /// ```
    /// Testimage::new_horizontal_line(9, 0..5);
    /// ```
    fn new_horizontal_line<I: Iterator<Item = usize>>(row: usize, cols: I) -> Self where Self::Item: Clone + Copy + Zero + One;
    /// returns a testimage that has `1` in `col` for all `rows` and `0` everywhere else
    ///
    /// ```
    /// Testimage::new_vertical_line(5..10, 0);
    /// ```
    fn new_vertical_line<I: Iterator<Item = usize>>(rows: I, col: usize) -> Self where Self::Item: Clone + Copy + Zero + One;
    /// # Panics
    /// panics unless all the values in `self` are between
    /// `0` (inclusive) and `1` (inclusive)
    fn luma01_to_image(&self) -> DynamicImage where Self::Item: Zero + One + FromPrimitive + ToPrimitive + PartialOrd + Float;
    /// # Panics
    /// panics unless all the values in `self` are between
    /// `0` (inclusive) and `1` (inclusive)
    fn save_luma01_to_png(&self, filename: &str) -> Result<(), ImageSaveError> where Self::Item: Zero + One + FromPrimitive + ToPrimitive + PartialOrd + Float;
    fn static_factors() -> Static<Self>
        where Self: Sized,
              Self::Item: Clone + Copy + Zero + One;
    fn horizontal_evolving_factors() -> Horizontal<Self> where Self::Item: Clone + Copy + Zero + One;
    fn vertical_evolving_factors() -> Vertical<Self> where Self::Item: Clone + Copy + Zero + One;
    fn linear_combination<C>(factors: &[Self], coefficients: &[C]) -> Self
        where C: Clone,
              Self: Sized + Mul<C, Output = Self>,
              Self::Item: Clone + Copy + Zero;
    fn normalize(&self) -> Self where Self::Item: Clone + BaseFloat;
    fn testimages() -> Test<Self> where Self::Item: Clone + Copy + Zero + One + BaseFloat;
}

impl<T> Testimage for DMat<T> {
    type Item = T;

    fn new_horizontal_line<I: Iterator<Item = usize>>(row: usize, cols: I) -> Self
        where Self::Item: Clone + Copy + Zero + One
    {
        let mut factor: DMat<Self::Item> = DMat::new_zeros(10, 10);
        for col in cols {
            *factor.index_mut((row, col)) = Self::Item::one();
        }
        factor
    }

    fn new_vertical_line<I: Iterator<Item = usize>>(rows: I, col: usize) -> Self
        where Self::Item: Clone + Copy + Zero + One
    {
        let mut factor: DMat<Self::Item> = DMat::new_zeros(10, 10);
        for row in rows {
            *factor.index_mut((row, col)) = Self::Item::one();
        }
        factor
    }

    fn luma01_to_image(&self) -> DynamicImage
        where Self::Item: Zero + One + FromPrimitive + ToPrimitive + PartialOrd + Float
    {
        let mut image_buffer = ImageBuffer::new(self.ncols() as u32, self.nrows() as u32);
        for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
            let value = self.index((y as usize, x as usize));
            assert!(Self::Item::zero() <= *value);
            assert!(*value <= Self::Item::one());
            let max = Self::Item::from_u8(std::u8::MAX).unwrap();
            let byte = (*value * max).round().to_u8().unwrap();
            *pixel = Luma([byte]);
        }
        DynamicImage::ImageLuma8(image_buffer)
    }

    fn save_luma01_to_png(&self, filename: &str) -> Result<(), ImageSaveError>
        where Self::Item: Zero + One + FromPrimitive + ToPrimitive + PartialOrd + Float
    {
        let image = self.luma01_to_image();
        let path = std::path::Path::new(filename);
        let mut file = try!(std::fs::File::create(&path).map_err(ImageSaveError::Io));
        image.save(&mut file, image::PNG).map_err(ImageSaveError::Image)
    }

    fn static_factors() -> Static<Self>
        where Self::Item: Clone + Copy + Zero + One
    {
        fn helper_horizontal<U: Clone + Copy + Zero + One>(row: usize) -> DMat<U> {
            Testimage::new_horizontal_line(row, 0..10)
        }
        fn helper_vertical<U: Clone + Copy + Zero + One>(col: usize) -> DMat<U> {
            Testimage::new_vertical_line(0..10, col)
        }
        once(Testimage::new_horizontal_line(9, 0..5))
            .chain((0..9).rev().map(helper_horizontal as fn(usize) -> Self))
            .chain(once(Testimage::new_vertical_line(5..10, 0)))
            .chain((1..10).map(helper_vertical as fn(usize) -> Self))
    }

    fn horizontal_evolving_factors() -> Horizontal<Self>
        where Self::Item: Clone + Copy + Zero + One
    {
        fn helper<U: Clone + Copy + Zero + One>(start_col: usize) -> DMat<U> {
            Testimage::new_horizontal_line(9, start_col..(start_col + 5))
        }
        (0..6).map(helper)
    }

    fn vertical_evolving_factors() -> Vertical<Self>
        where Self::Item: Clone + Copy + Zero + One
    {
        fn helper<U: Clone + Copy + Zero + One>(start_row: usize) -> DMat<U> {
            Testimage::new_vertical_line(start_row..(start_row + 5), 0)
        }
        (0..6).rev().map(helper)
    }

    fn linear_combination<C>(factors: &[Self], coefficients: &[C]) -> Self
        where C: Clone,
              Self: Mul<C, Output = Self>,
              Self::Item: Clone + Copy + Zero
    {
        assert!(0 < factors.len());
        assert_eq!(factors.len(), coefficients.len());
        let nrows = factors[0].nrows();
        let ncols = factors[0].ncols();
        let mut result = DMat::new_zeros(nrows, ncols);
        for (factor, coefficient) in factors.iter().zip(coefficients.iter()) {
            assert_eq!(factor.nrows(), nrows);
            assert_eq!(factor.ncols(), ncols);
            result = result.add(factor.clone().mul(coefficient.clone()));
        }
        result
    }

    fn normalize(&self) -> Self
        where Self::Item: Clone + BaseFloat
    {
        let nrows = self.nrows();
        let ncols = self.ncols();
        let mut vec = DVec::from_slice(nrows * ncols, self.as_vec());
        vec.normalize_mut();
        DMat::from_col_vec(nrows, ncols, vec.as_slice())
    }

    fn testimages() -> Test<Self>
        where Self::Item: Clone + Copy + Zero + One + BaseFloat
    {
        fn helper<U, V, W>((a, b): (U, V)) -> W
            where U: Add<V, Output = W>,
                  W: Testimage,
                  W::Item: Clone + BaseFloat
        {
            a.add(b).normalize()
        }
        Testimage::horizontal_evolving_factors()
            .zip(Testimage::vertical_evolving_factors())
            .map(helper)

        //     horizontal
        //     .zip(vertical)
        //     .enumerate()
        //     .map(|(step, (horizontal, vertical))| {
        //         // let h: Self = horizontal;
        //         // // let cloned: Self = (*horizontal).clone::<Self>();
        //         // let foo = h.add(vertical);
        //         // let result: Self = foo.normalize::<Self>();
        //         // result
        //         horizontal.clone()
        //     }))
    }
}

// fn random_coefficient<R: Rng>(rng: &mut R) -> FloatType {
//     let Closed01(random) = rng.gen::<Closed01<FloatType>>();
//     random
// }
//
// fn random_coefficients<R: Rng>(rng: &mut R, count: usize) -> DVec<FloatType> {
//     let mut coefficients: DVec<FloatType> = DVec::new_zeros(count);
//     for i in 0..count {
//         coefficients[i] = random_coefficient(rng);
//     }
//     coefficients
// }
<commit_msg>make normalization work<commit_after>/// generates images used to test NMF

use std::ops::{Index, IndexMut, Mul, Add, Div};

use std;

use std::cmp::PartialOrd;

use std::ops::Range;
use std::iter::{Map, Rev, once, Once, Chain, Zip};

extern crate num;
use num::traits::{Zero, One, FromPrimitive, ToPrimitive, Float};

extern crate nalgebra;
use nalgebra::{DMat, DVec, Norm, BaseFloat};

extern crate image;
use self::image::{ImageBuffer, Luma, DynamicImage};

use partialmax::PartialMaxIteratorExt;

quick_error! {
    #[derive(Debug)]
    pub enum ImageSaveError {
        /// an error has occured when opening the file
        Io(err: std::io::Error) {}
        /// an error has occured when writing the image into the file
        Image(err: image::ImageError) {}
    }
}

// TODO suffix ReturnT
pub type Horizontal<T> = Map<Range<usize>, fn(usize) -> T>;
pub type Vertical<T> = Map<Rev<Range<usize>>, fn(usize) -> T>;
pub type Static<T> = Chain<Chain<Chain<Once<T>, Vertical<T>>, Once<T>>, Horizontal<T>>;
pub type Test<T> = Map<Zip<Horizontal<T>, Vertical<T>>, fn((T, T)) -> T>;

// TODO move the type constraints back up here
// TODO split into multiple traits
// normalize
// images
// creation
pub trait Testimage<T> {
    type Item;

    /// returns a testimage that has `1` in `row` for all `cols` and `0` everywhere else
    ///
    /// ```
    /// Testimage::new_horizontal_line(9, 0..5);
    /// ```
    fn new_horizontal_line<I: Iterator<Item = usize>>(row: usize, cols: I) -> Self where Self::Item: Clone + Copy + Zero + One;
    /// returns a testimage that has `1` in `col` for all `rows` and `0` everywhere else
    ///
    /// ```
    /// Testimage::new_vertical_line(5..10, 0);
    /// ```
    fn new_vertical_line<I: Iterator<Item = usize>>(rows: I, col: usize) -> Self where Self::Item: Clone + Copy + Zero + One;
    /// # Panics
    /// panics unless all the values in `self` are between
    /// `0` (inclusive) and `1` (inclusive)
    fn luma01_to_image(&self) -> DynamicImage where Self::Item: Zero + One + FromPrimitive + ToPrimitive + PartialOrd + Float;
    /// # Panics
    /// panics unless all the values in `self` are between
    /// `0` (inclusive) and `1` (inclusive)
    fn save_luma01_to_png(&self, filename: &str) -> Result<(), ImageSaveError> where Self::Item: Zero + One + FromPrimitive + ToPrimitive + PartialOrd + Float;
    fn static_factors() -> Static<Self>
        where Self: Sized,
              Self::Item: Clone + Copy + Zero + One;
    // TODO it's probably a much better idea to just use plain functions here
    fn horizontal_evolving_factors() -> Horizontal<Self> where Self::Item: Clone + Copy + Zero + One;
    fn vertical_evolving_factors() -> Vertical<Self> where Self::Item: Clone + Copy + Zero + One;
    // TODO trait
    fn linear_combination<C>(factors: &[Self], coefficients: &[C]) -> Self
        where C: Clone,
              Self: Sized + Mul<C, Output = Self>,
              Self::Item: Clone + Copy + Zero;
    fn normalize_mut(self) -> Self
        where Self::Item: Clone + Copy + BaseFloat,
              Self: Div<T, Output = Self>,
              Self: Sized;
    fn testimages() -> Test<Self> where Self::Item: Clone + Copy + Zero + One + BaseFloat;
}

impl<T> Testimage<T> for DMat<T> {
    // here's where we associate Self::Item and T
    type Item = T;

    fn new_horizontal_line<I: Iterator<Item = usize>>(row: usize, cols: I) -> Self
        where Self::Item: Clone + Copy + Zero + One
    {
        let mut factor: DMat<Self::Item> = DMat::new_zeros(10, 10);
        for col in cols {
            *factor.index_mut((row, col)) = Self::Item::one();
        }
        factor
    }

    fn new_vertical_line<I: Iterator<Item = usize>>(rows: I, col: usize) -> Self
        where Self::Item: Clone + Copy + Zero + One
    {
        let mut factor: DMat<Self::Item> = DMat::new_zeros(10, 10);
        for row in rows {
            *factor.index_mut((row, col)) = Self::Item::one();
        }
        factor
    }

    fn luma01_to_image(&self) -> DynamicImage
        where Self::Item: Zero + One + FromPrimitive + ToPrimitive + PartialOrd + Float
    {
        let mut image_buffer = ImageBuffer::new(self.ncols() as u32, self.nrows() as u32);
        for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
            let value = self.index((y as usize, x as usize));
            assert!(Self::Item::zero() <= *value);
            assert!(*value <= Self::Item::one());
            let max = Self::Item::from_u8(std::u8::MAX).unwrap();
            let byte = (*value * max).round().to_u8().unwrap();
            *pixel = Luma([byte]);
        }
        DynamicImage::ImageLuma8(image_buffer)
    }

    fn save_luma01_to_png(&self, filename: &str) -> Result<(), ImageSaveError>
        where Self::Item: Zero + One + FromPrimitive + ToPrimitive + PartialOrd + Float
    {
        let image = self.luma01_to_image();
        let path = std::path::Path::new(filename);
        let mut file = try!(std::fs::File::create(&path).map_err(ImageSaveError::Io));
        image.save(&mut file, image::PNG).map_err(ImageSaveError::Image)
    }

    fn static_factors() -> Static<Self>
        where Self::Item: Clone + Copy + Zero + One
    {
        fn helper_horizontal<U: Clone + Copy + Zero + One>(row: usize) -> DMat<U> {
            Testimage::new_horizontal_line(row, 0..10)
        }
        fn helper_vertical<U: Clone + Copy + Zero + One>(col: usize) -> DMat<U> {
            Testimage::new_vertical_line(0..10, col)
        }
        once(Testimage::new_horizontal_line(9, 0..5))
            .chain((0..9).rev().map(helper_horizontal as fn(usize) -> Self))
            .chain(once(Testimage::new_vertical_line(5..10, 0)))
            .chain((1..10).map(helper_vertical as fn(usize) -> Self))
    }

    fn horizontal_evolving_factors() -> Horizontal<Self>
        where Self::Item: Clone + Copy + Zero + One
    {
        fn helper<U: Clone + Copy + Zero + One>(start_col: usize) -> DMat<U> {
            Testimage::new_horizontal_line(9, start_col..(start_col + 5))
        }
        (0..6).map(helper)
    }

    fn vertical_evolving_factors() -> Vertical<Self>
        where Self::Item: Clone + Copy + Zero + One
    {
        fn helper<U: Clone + Copy + Zero + One>(start_row: usize) -> DMat<U> {
            Testimage::new_vertical_line(start_row..(start_row + 5), 0)
        }
        (0..6).rev().map(helper)
    }

    fn linear_combination<C>(factors: &[Self], coefficients: &[C]) -> Self
        where C: Clone,
              Self: Mul<C, Output = Self>,
              Self::Item: Clone + Copy + Zero
    {
        assert!(0 < factors.len());
        assert_eq!(factors.len(), coefficients.len());
        let nrows = factors[0].nrows();
        let ncols = factors[0].ncols();
        let mut result = DMat::new_zeros(nrows, ncols);
        for (factor, coefficient) in factors.iter().zip(coefficients.iter()) {
            assert_eq!(factor.nrows(), nrows);
            assert_eq!(factor.ncols(), ncols);
            result = result.add(factor.clone().mul(coefficient.clone()));
        }
        result
    }

    /// divide all values by max value
    // TODO put this into its own trait
    fn normalize_mut(self) -> Self
        where Self::Item: Clone + Copy + PartialOrd,
              Self: Div<T, Output = Self>,
              Self: Sized
    {
        let nrows = self.nrows();
        let ncols = self.ncols();
        let max = self.as_vec().iter().cloned().partial_max().unwrap();
        self.div(max)
    }

    fn testimages() -> Test<Self>
        where Self::Item: Clone + Copy + Zero + One + BaseFloat
    {
        fn helper<U, V, W, X>((a, b): (U, V)) -> W
            where U: Add<V, Output = W>,
                  W: Testimage<X>,
                  W::Item: Clone + BaseFloat,
                  W: Div<X, Output=W>
        {
            a.add(b).normalize_mut()
        }
        Testimage::horizontal_evolving_factors()
            .zip(Testimage::vertical_evolving_factors())
            .map(helper)

        //     horizontal
        //     .zip(vertical)
        //     .enumerate()
        //     .map(|(step, (horizontal, vertical))| {
        //         // let h: Self = horizontal;
        //         // // let cloned: Self = (*horizontal).clone::<Self>();
        //         // let foo = h.add(vertical);
        //         // let result: Self = foo.normalize::<Self>();
        //         // result
        //         horizontal.clone()
        //     }))
    }
}

// fn random_coefficient<R: Rng>(rng: &mut R) -> FloatType {
//     let Closed01(random) = rng.gen::<Closed01<FloatType>>();
//     random
// }
//
// fn random_coefficients<R: Rng>(rng: &mut R, count: usize) -> DVec<FloatType> {
//     let mut coefficients: DVec<FloatType> = DVec::new_zeros(count);
//     for i in 0..count {
//         coefficients[i] = random_coefficient(rng);
//     }
//     coefficients
// }
<|endoftext|>