<commit_before>//! Vectored I/O

use crate::Result;
use crate::errno::Errno;
use libc::{self, c_int, c_void, size_t, off_t};
use std::marker::PhantomData;
use std::os::unix::io::RawFd;

/// Low-level vectored write to a raw file descriptor
///
/// See also [writev(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html)
pub fn writev(fd: RawFd, iov: &[IoVec<&[u8]>]) -> Result<usize> {
    let res = unsafe { libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) };

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

/// Low-level vectored read from a raw file descriptor
///
/// See also [readv(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html)
pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result<usize> {
    let res = unsafe { libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) };

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

/// Write to `fd` at `offset` from buffers in `iov`.
///
/// Buffers in `iov` will be written in order until all buffers have been written
/// or an error occurs. The file offset is not changed.
///
/// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html)
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>],
               offset: off_t) -> Result<usize> {
    #[cfg(target_env = "uclibc")]
    let offset = offset as libc::off64_t; // uclibc doesn't use off_t
    let res = unsafe {
        libc::pwritev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset)
    };

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

/// Read from `fd` at `offset` filling buffers in `iov`.
///
/// Buffers in `iov` will be filled in order until all buffers have been filled,
/// no more bytes are available, or an error occurs. The file offset is not
/// changed.
///
/// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html)
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>],
              offset: off_t) -> Result<usize> {
    #[cfg(target_env = "uclibc")]
    let offset = offset as libc::off64_t; // uclibc doesn't use off_t
    let res = unsafe {
        libc::preadv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset)
    };

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

/// Low-level write to a file, with specified offset.
///
/// See also [pwrite(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html)
// TODO: move to unistd
pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> {
    let res = unsafe {
        libc::pwrite(fd, buf.as_ptr() as *const c_void, buf.len() as size_t,
                    offset)
    };

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

/// Low-level write to a file, with specified offset.
///
/// See also [pread(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html)
// TODO: move to unistd
pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{
    let res = unsafe {
        libc::pread(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t,
                   offset)
    };

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

/// A slice of memory in a remote process, starting at address `base`
/// and consisting of `len` bytes.
///
/// This is the same underlying C structure as [`IoVec`](struct.IoVec.html),
/// except that it refers to memory in some other process, and is
/// therefore not represented in Rust by an actual slice as `IoVec` is. It
/// is used with [`process_vm_readv`](fn.process_vm_readv.html)
/// and [`process_vm_writev`](fn.process_vm_writev.html).
#[cfg(target_os = "linux")]
#[cfg_attr(docsrs, doc(cfg(all())))]
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct RemoteIoVec {
    /// The starting address of this slice (`iov_base`).
    pub base: usize,
    /// The number of bytes in this slice (`iov_len`).
    pub len: usize,
}

feature! {
#![feature = "process"]

/// Write data directly to another process's virtual memory
/// (see [`process_vm_writev`(2)]).
///
/// `local_iov` is a list of [`IoVec`]s containing the data to be written,
/// and `remote_iov` is a list of [`RemoteIoVec`]s identifying where the
/// data should be written in the target process. On success, returns the
/// number of bytes written, which will always be a whole
/// number of `remote_iov` chunks.
///
/// This requires the same permissions as debugging the process using
/// [ptrace]: you must either be a privileged process (with
/// `CAP_SYS_PTRACE`), or you must be running as the same user as the
/// target process and the OS must have unprivileged debugging enabled.
///
/// This function is only available on Linux.
///
/// [`process_vm_writev`(2)]: https://man7.org/linux/man-pages/man2/process_vm_writev.2.html
/// [ptrace]: ../ptrace/index.html
/// [`IoVec`]: struct.IoVec.html
/// [`RemoteIoVec`]: struct.RemoteIoVec.html
#[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
pub fn process_vm_writev(
    pid: crate::unistd::Pid,
    local_iov: &[IoVec<&[u8]>],
    remote_iov: &[RemoteIoVec]) -> Result<usize>
{
    let res = unsafe {
        libc::process_vm_writev(pid.into(),
                                local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
                                remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
    };

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

/// Read data directly from another process's virtual memory
/// (see [`process_vm_readv`(2)]).
///
/// `local_iov` is a list of [`IoVec`]s containing the buffer to copy
/// data into, and `remote_iov` is a list of [`RemoteIoVec`]s identifying
/// where the source data is in the target process. On success,
/// returns the number of bytes written, which will always be a whole
/// number of `remote_iov` chunks.
///
/// This requires the same permissions as debugging the process using
/// [`ptrace`]: you must either be a privileged process (with
/// `CAP_SYS_PTRACE`), or you must be running as the same user as the
/// target process and the OS must have unprivileged debugging enabled.
///
/// This function is only available on Linux.
///
/// [`process_vm_readv`(2)]: https://man7.org/linux/man-pages/man2/process_vm_readv.2.html
/// [`ptrace`]: ../ptrace/index.html
/// [`IoVec`]: struct.IoVec.html
/// [`RemoteIoVec`]: struct.RemoteIoVec.html
#[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
pub fn process_vm_readv(
    pid: crate::unistd::Pid,
    local_iov: &[IoVec<&mut [u8]>],
    remote_iov: &[RemoteIoVec]) -> Result<usize>
{
    let res = unsafe {
        libc::process_vm_readv(pid.into(),
                               local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
                               remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
    };

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

/// A vector of buffers.
///
/// Vectored I/O methods like [`writev`] and [`readv`] use this structure for
/// both reading and writing.  Each `IoVec` specifies the base address and
/// length of an area in memory.
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct IoVec<T>(pub(crate) libc::iovec, PhantomData<T>);

impl<T> IoVec<T> {
    /// View the `IoVec` as a Rust slice.
    #[inline]
    pub fn as_slice(&self) -> &[u8] {
        use std::slice;

        unsafe {
            slice::from_raw_parts(
                self.0.iov_base as *const u8,
                self.0.iov_len as usize)
        }
    }
}

impl<'a> IoVec<&'a [u8]> {
    #[cfg(all(feature = "mount", target_os = "freebsd"))]
    pub(crate) fn from_raw_parts(base: *mut c_void, len: usize) -> Self {
        IoVec(libc::iovec {
            iov_base: base,
            iov_len: len
        }, PhantomData)
    }

    /// Create an `IoVec` from a Rust slice.
    pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> {
        IoVec(libc::iovec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t,
        }, PhantomData)
    }
}

impl<'a> IoVec<&'a mut [u8]> {
    /// Create an `IoVec` from a mutable Rust slice.
    pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> {
        IoVec(libc::iovec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t,
        }, PhantomData)
    }
}

// The only reason IoVec isn't automatically Send+Sync is because libc::iovec
// contains raw pointers.
unsafe impl<T> Send for IoVec<T> where T: Send {}
unsafe impl<T> Sync for IoVec<T> where T: Sync {}
<commit_msg>Fix typo in pread docs<commit_after>//! Vectored I/O

use crate::Result;
use crate::errno::Errno;
use libc::{self, c_int, c_void, size_t, off_t};
use std::marker::PhantomData;
use std::os::unix::io::RawFd;

/// Low-level vectored write to a raw file descriptor
///
/// See also [writev(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html)
pub fn writev(fd: RawFd, iov: &[IoVec<&[u8]>]) -> Result<usize> {
    let res = unsafe { libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) };

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

/// Low-level vectored read from a raw file descriptor
///
/// See also [readv(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html)
pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result<usize> {
    let res = unsafe { libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) };

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

/// Write to `fd` at `offset` from buffers in `iov`.
///
/// Buffers in `iov` will be written in order until all buffers have been written
/// or an error occurs. The file offset is not changed.
///
/// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html)
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>],
               offset: off_t) -> Result<usize> {
    #[cfg(target_env = "uclibc")]
    let offset = offset as libc::off64_t; // uclibc doesn't use off_t
    let res = unsafe {
        libc::pwritev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset)
    };

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

/// Read from `fd` at `offset` filling buffers in `iov`.
///
/// Buffers in `iov` will be filled in order until all buffers have been filled,
/// no more bytes are available, or an error occurs. The file offset is not
/// changed.
///
/// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html)
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>],
              offset: off_t) -> Result<usize> {
    #[cfg(target_env = "uclibc")]
    let offset = offset as libc::off64_t; // uclibc doesn't use off_t
    let res = unsafe {
        libc::preadv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset)
    };

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

/// Low-level write to a file, with specified offset.
///
/// See also [pwrite(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html)
// TODO: move to unistd
pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> {
    let res = unsafe {
        libc::pwrite(fd, buf.as_ptr() as *const c_void, buf.len() as size_t,
                    offset)
    };

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

/// Low-level read from a file, with specified offset.
///
/// See also [pread(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html)
// TODO: move to unistd
pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{
    let res = unsafe {
        libc::pread(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t,
                   offset)
    };

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

/// A slice of memory in a remote process, starting at address `base`
/// and consisting of `len` bytes.
///
/// This is the same underlying C structure as [`IoVec`](struct.IoVec.html),
/// except that it refers to memory in some other process, and is
/// therefore not represented in Rust by an actual slice as `IoVec` is. It
/// is used with [`process_vm_readv`](fn.process_vm_readv.html)
/// and [`process_vm_writev`](fn.process_vm_writev.html).
#[cfg(target_os = "linux")]
#[cfg_attr(docsrs, doc(cfg(all())))]
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct RemoteIoVec {
    /// The starting address of this slice (`iov_base`).
    pub base: usize,
    /// The number of bytes in this slice (`iov_len`).
    pub len: usize,
}

feature! {
#![feature = "process"]

/// Write data directly to another process's virtual memory
/// (see [`process_vm_writev`(2)]).
///
/// `local_iov` is a list of [`IoVec`]s containing the data to be written,
/// and `remote_iov` is a list of [`RemoteIoVec`]s identifying where the
/// data should be written in the target process. On success, returns the
/// number of bytes written, which will always be a whole
/// number of `remote_iov` chunks.
///
/// This requires the same permissions as debugging the process using
/// [ptrace]: you must either be a privileged process (with
/// `CAP_SYS_PTRACE`), or you must be running as the same user as the
/// target process and the OS must have unprivileged debugging enabled.
///
/// This function is only available on Linux.
///
/// [`process_vm_writev`(2)]: https://man7.org/linux/man-pages/man2/process_vm_writev.2.html
/// [ptrace]: ../ptrace/index.html
/// [`IoVec`]: struct.IoVec.html
/// [`RemoteIoVec`]: struct.RemoteIoVec.html
#[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
pub fn process_vm_writev(
    pid: crate::unistd::Pid,
    local_iov: &[IoVec<&[u8]>],
    remote_iov: &[RemoteIoVec]) -> Result<usize>
{
    let res = unsafe {
        libc::process_vm_writev(pid.into(),
                                local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
                                remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
    };

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

/// Read data directly from another process's virtual memory
/// (see [`process_vm_readv`(2)]).
///
/// `local_iov` is a list of [`IoVec`]s containing the buffer to copy
/// data into, and `remote_iov` is a list of [`RemoteIoVec`]s identifying
/// where the source data is in the target process. On success,
/// returns the number of bytes written, which will always be a whole
/// number of `remote_iov` chunks.
///
/// This requires the same permissions as debugging the process using
/// [`ptrace`]: you must either be a privileged process (with
/// `CAP_SYS_PTRACE`), or you must be running as the same user as the
/// target process and the OS must have unprivileged debugging enabled.
///
/// This function is only available on Linux.
///
/// [`process_vm_readv`(2)]: https://man7.org/linux/man-pages/man2/process_vm_readv.2.html
/// [`ptrace`]: ../ptrace/index.html
/// [`IoVec`]: struct.IoVec.html
/// [`RemoteIoVec`]: struct.RemoteIoVec.html
#[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
pub fn process_vm_readv(
    pid: crate::unistd::Pid,
    local_iov: &[IoVec<&mut [u8]>],
    remote_iov: &[RemoteIoVec]) -> Result<usize>
{
    let res = unsafe {
        libc::process_vm_readv(pid.into(),
                               local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
                               remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
    };

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

/// A vector of buffers.
///
/// Vectored I/O methods like [`writev`] and [`readv`] use this structure for
/// both reading and writing.  Each `IoVec` specifies the base address and
/// length of an area in memory.
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct IoVec<T>(pub(crate) libc::iovec, PhantomData<T>);

impl<T> IoVec<T> {
    /// View the `IoVec` as a Rust slice.
    #[inline]
    pub fn as_slice(&self) -> &[u8] {
        use std::slice;

        unsafe {
            slice::from_raw_parts(
                self.0.iov_base as *const u8,
                self.0.iov_len as usize)
        }
    }
}

impl<'a> IoVec<&'a [u8]> {
    #[cfg(all(feature = "mount", target_os = "freebsd"))]
    pub(crate) fn from_raw_parts(base: *mut c_void, len: usize) -> Self {
        IoVec(libc::iovec {
            iov_base: base,
            iov_len: len
        }, PhantomData)
    }

    /// Create an `IoVec` from a Rust slice.
    pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> {
        IoVec(libc::iovec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t,
        }, PhantomData)
    }
}

impl<'a> IoVec<&'a mut [u8]> {
    /// Create an `IoVec` from a mutable Rust slice.
    pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> {
        IoVec(libc::iovec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t,
        }, PhantomData)
    }
}

// The only reason IoVec isn't automatically Send+Sync is because libc::iovec
// contains raw pointers.
unsafe impl<T> Send for IoVec<T> where T: Send {}
unsafe impl<T> Sync for IoVec<T> where T: Sync {}
<|endoftext|>


<commit_before>use std::cmp;

use crate::clean::{self, DocFragment, DocFragmentKind, Item};
use crate::core::DocContext;
use crate::fold::{self, DocFolder};
use crate::passes::Pass;

#[cfg(test)]
mod tests;

pub const UNINDENT_COMMENTS: Pass = Pass {
    name: "unindent-comments",
    run: unindent_comments,
    description: "removes excess indentation on comments in order for markdown to like it",
};

pub fn unindent_comments(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
    CommentCleaner.fold_crate(krate)
}

struct CommentCleaner;

impl fold::DocFolder for CommentCleaner {
    fn fold_item(&mut self, mut i: Item) -> Option<Item> {
        i.attrs.unindent_doc_comments();
        self.fold_item_recur(i)
    }
}

impl clean::Attributes {
    pub fn unindent_doc_comments(&mut self) {
        unindent_fragments(&mut self.doc_strings);
    }
}

fn unindent_fragments(docs: &mut Vec<DocFragment>) {
    let mut saw_first_line = false;
    let mut saw_second_line = false;

    let add = if !docs.windows(2).all(|arr| arr[0].kind == arr[1].kind)
        && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc)
    {
        // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to
        // "decide" how much the minimum indent will be.
        1
    } else {
        0
    };

    let min_indent = match docs
        .iter()
        .map(|fragment| {
            fragment.doc.lines().fold(usize::MAX, |min_indent, line| {
                // After we see the first non-whitespace line, look at
                // the line we have. If it is not whitespace, and therefore
                // part of the first paragraph, then ignore the indentation
                // level of the first line
                let ignore_previous_indents =
                    saw_first_line && !saw_second_line && !line.chars().all(|c| c.is_whitespace());

                let min_indent = if ignore_previous_indents { usize::MAX } else { min_indent };

                if saw_first_line {
                    saw_second_line = true;
                }

                if line.chars().all(|c| c.is_whitespace()) {
                    min_indent
                } else {
                    saw_first_line = true;
                    // Compare against either space or tab, ignoring whether they are
                    // mixed or not.
                    let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count();
                    cmp::min(min_indent, whitespace)
                        + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add }
                }
            })
        })
        .min()
    {
        Some(x) => x,
        None => return,
    };

    let mut first_ignored = false;
    for fragment in docs {
        let lines: Vec<_> = fragment.doc.lines().collect();

        if !lines.is_empty() {
            let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 {
                min_indent - add
            } else {
                min_indent
            };

            let mut iter = lines.iter();
            let mut result = if !first_ignored {
                first_ignored = true;
                vec![iter.next().unwrap().trim_start().to_string()]
            } else {
                Vec::new()
            };
            result.extend_from_slice(
                &iter
                    .map(|&line| {
                        if line.chars().all(|c| c.is_whitespace()) {
                            line.to_string()
                        } else {
                            assert!(line.len() >= min_indent);
                            line[min_indent..].to_string()
                        }
                    })
                    .collect::<Vec<_>>(),
            );
            fragment.doc = result.join("\n");
        }
    }
}
<commit_msg>Change a bit how the first doc comment lines are handled<commit_after>use std::cmp;

use crate::clean::{self, DocFragment, DocFragmentKind, Item};
use crate::core::DocContext;
use crate::fold::{self, DocFolder};
use crate::passes::Pass;

#[cfg(test)]
mod tests;

pub const UNINDENT_COMMENTS: Pass = Pass {
    name: "unindent-comments",
    run: unindent_comments,
    description: "removes excess indentation on comments in order for markdown to like it",
};

pub fn unindent_comments(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
    CommentCleaner.fold_crate(krate)
}

struct CommentCleaner;

impl fold::DocFolder for CommentCleaner {
    fn fold_item(&mut self, mut i: Item) -> Option<Item> {
        i.attrs.unindent_doc_comments();
        self.fold_item_recur(i)
    }
}

impl clean::Attributes {
    pub fn unindent_doc_comments(&mut self) {
        unindent_fragments(&mut self.doc_strings);
    }
}

fn unindent_fragments(docs: &mut Vec<DocFragment>) {
    // `add` is used in case the most common sugared doc syntax is used ("/// "). The other
    // fragments kind's lines are never starting with a whitespace unless they are using some
    // markdown formatting requiring it. Therefore, if the doc block have a mix between the two,
    // we need to take into account the fact that the minimum indent minus one (to take this
    // whitespace into account).
    //
    // For example:
    //
    // /// hello!
    // #[doc = "another"]
    //
    // In this case, you want "hello! another" and not "hello!  another".
    let add = if !docs.windows(2).all(|arr| arr[0].kind == arr[1].kind)
        && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc)
    {
        // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to
        // "decide" how much the minimum indent will be.
        1
    } else {
        0
    };

    // `min_indent` is used to know how much whitespaces from the start of each lines must be
    // removed. Example:
    //
    // ///     hello!
    // #[doc = "another"]
    //
    // In here, the `min_indent` is 1 (because non-sugared fragment are always counted with minimum
    // 1 whitespace), meaning that "hello!" will be considered a codeblock because it starts with 4
    // (5 - 1) whitespaces.
    let min_indent = match docs
        .iter()
        .map(|fragment| {
            fragment.doc.lines().fold(usize::MAX, |min_indent, line| {
                if line.chars().all(|c| c.is_whitespace()) {
                    min_indent
                } else {
                    // Compare against either space or tab, ignoring whether they are
                    // mixed or not.
                    let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count();
                    cmp::min(min_indent, whitespace)
                        + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add }
                }
            })
        })
        .min()
    {
        Some(x) => x,
        None => return,
    };

    for fragment in docs {
        let lines: Vec<_> = fragment.doc.lines().collect();

        if !lines.is_empty() {
            let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 {
                min_indent - add
            } else {
                min_indent
            };

            fragment.doc = lines
                .iter()
                .map(|&line| {
                    if line.chars().all(|c| c.is_whitespace()) {
                        line.to_string()
                    } else {
                        assert!(line.len() >= min_indent);
                        line[min_indent..].to_string()
                    }
                })
                .collect::<Vec<_>>()
                .join("\n");
        }
    }
}
<|endoftext|>


<commit_before>#![crate_id="find_max"]
//! Test various syntaxes to find the maximum value of a vector using generic function.
//!
//! @license MIT license <http://www.opensource.org/licenses/mit-license.php>

#[cfg(test)]
extern crate test;

#[cfg(test)]
use test::Bencher;

/**
 * Code from Rust MeetUp (March, 31st 2014) at Mozilla Space, Paris.
 * https://reps.mozilla.org/e/meetup-rust-paris-02/
 */
fn find_max1<'a, T: Ord>(lst: &'a Vec<T>) -> Option<&'a T> {
	let mut max = None;

	for i in lst.iter() {
		max = match max {
			None => Some(i),
			Some(ref m) if i > *m => Some(i),
			_ => max
		}
	}
	max
}

/**
 * Using a closure.
 *
 * Inspired by tutorial "15 Closure"
 * http://doc.rust-lang.org/tutorial.html#closures
 */
fn find_max2<'a, T: Ord>(lst: &'a Vec<T>) -> Option<&'a T> {
	let mut max = None;

	let find_max = |i: &'a T| {
		max = match max {
			None => Some(i),
			Some(ref m) if i > *m => Some(i),
			_ => max
		}
	};
	for x in lst.iter() {
		find_max(x);
	}

	max
}

/**
 * Using a closure and .map().
 */
fn find_max3<'a, T: Ord>(lst: &'a Vec<T>) -> Option<&'a T> {
	let mut max = None;

	let find_max = |i: &'a T| {
		max = match max {
			None => Some(i),
			Some(ref m) if i > *m => Some(i),
			_ => max
		};
		max
	};
	lst.iter().map(find_max).last().unwrap()
}

#[test]
fn test_find_max1() {
	let v = vec!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	let nine = 9;
	assert_eq!(Some(&nine), find_max1(&v));
}

#[test]
fn test_find_max2() {
	let v = vec!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	let nine = 9;
	assert_eq!(Some(&nine), find_max2(&v));
}

#[test]
fn test_find_max3() {
	let v = vec!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	let nine = 9;
	assert_eq!(Some(&nine), find_max3(&v));
}

#[bench]
fn bench_find_max1(b: &mut Bencher) {
	let v = vec!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	b.iter(|| {
		find_max1(&v);
	});
}

#[bench]
fn bench_find_max2(b: &mut Bencher) {
	let v = vec!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	b.iter(|| {
		find_max2(&v);
	});
}

#[bench]
fn bench_find_max3(b: &mut Bencher) {
	let v = vec!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	b.iter(|| {
		find_max3(&v);
	});
}

#[cfg(not(test))]
fn main () {
	let int_v = vec!(5, 2, 0, 8, 2);
	println!("find_max1 -> {}", find_max1(&int_v));
	println!("find_max2 -> {}", find_max2(&int_v));
	println!("find_max3 -> {}", find_max3(&int_v));
	let v = vec!("qehgesrhsetha", "bqthst", "cthersth");
	let b = find_max3(&v);
	println!("{}", b);

	println!("{}", v);
	println!("{}", b);
	// simply using stdlib:
	println!("{}", v.iter().max_by(|x| *x).unwrap())
}
<commit_msg>find_max.rs : move std expression into function to test and bench.<commit_after>#![crate_id="find_max"]
//! Test various syntaxes to find the maximum value of a vector using generic function.
//!
//! @license MIT license <http://www.opensource.org/licenses/mit-license.php>

#[cfg(test)]
extern crate test;

#[cfg(test)]
use test::Bencher;

/**
 * Code from Rust MeetUp (March, 31st 2014) at Mozilla Space, Paris.
 * https://reps.mozilla.org/e/meetup-rust-paris-02/
 */
fn find_max1<'a, T: Ord>(lst: &'a Vec<T>) -> Option<&'a T> {
	let mut max = None;

	for i in lst.iter() {
		max = match max {
			None => Some(i),
			Some(ref m) if i > *m => Some(i),
			_ => max
		}
	}
	max
}

/**
 * Using a closure.
 *
 * Inspired by tutorial "15 Closure"
 * http://doc.rust-lang.org/tutorial.html#closures
 */
fn find_max2<'a, T: Ord>(lst: &'a Vec<T>) -> Option<&'a T> {
	let mut max = None;

	let find_max = |i: &'a T| {
		max = match max {
			None => Some(i),
			Some(ref m) if i > *m => Some(i),
			_ => max
		}
	};
	for x in lst.iter() {
		find_max(x);
	}

	max
}

/**
 * Using a closure and .map().
 */
fn find_max3<'a, T: Ord>(lst: &'a Vec<T>) -> Option<&'a T> {
	let mut max = None;

	let find_max = |i: &'a T| {
		max = match max {
			None => Some(i),
			Some(ref m) if i > *m => Some(i),
			_ => max
		};
		max
	};
	lst.iter().map(find_max).last().unwrap()
}

/**
 * Using std lib
 */
fn find_maxstd<'a, T: TotalOrd>(lst: &'a Vec<T>) -> Option<&'a T> {
	lst.iter().max_by(|x| *x)
}

#[test]
fn test_find_max1() {
	let v = vec!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	let nine = 9;
	assert_eq!(Some(&nine), find_max1(&v));
}

#[test]
fn test_find_max2() {
	let v = vec!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	let nine = 9;
	assert_eq!(Some(&nine), find_max2(&v));
}

#[test]
fn test_find_max3() {
	let v = vec!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	let nine = 9;
	assert_eq!(Some(&nine), find_max3(&v));
}

#[test]
fn test_find_maxstd() {
	let v = vec!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	let nine = 9;
	assert_eq!(Some(&nine), find_maxstd(&v));
}

#[bench]
fn bench_find_max1(b: &mut Bencher) {
	let v = vec!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	b.iter(|| {
		find_max1(&v);
	});
}

#[bench]
fn bench_find_max2(b: &mut Bencher) {
	let v = vec!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	b.iter(|| {
		find_max2(&v);
	});
}

#[bench]
fn bench_find_max3(b: &mut Bencher) {
	let v = vec!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	b.iter(|| {
		find_max3(&v);
	});
}

#[bench]
fn bench_find_maxstd(b: &mut Bencher) {
	let v = vec!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	b.iter(|| {
		find_maxstd(&v);
	});
}

#[cfg(not(test))]
fn main () {
	let int_v = vec!(5, 2, 0, 8, 2);
	println!("find_max1 -> {}", find_max1(&int_v));
	println!("find_max2 -> {}", find_max2(&int_v));
	println!("find_max3 -> {}", find_max3(&int_v));
	println!("find_maxstd -> {}", find_maxstd(&int_v));
	let v = vec!("qehgesrhsetha", "bqthst", "cthersth");
	let b = find_max3(&v);
	println!("{}", b);

	println!("{}", v);
	println!("{}", b);
}
<|endoftext|>


<commit_before>use luminance::{Dim2, Flat, Sampler, Texture};
use image;
use std::ops::Deref;
use std::path::Path;

pub use luminance::RGBA32F;

use resource::{Cache, Load, LoadError, Reload, Result};

/// Load an RGBA texture from an image at a path.
pub fn load_rgba_texture<P>(path: P, sampler: &Sampler, linear: bool) -> Result<Texture<Flat, Dim2, RGBA32F>> where P: AsRef<Path> {
  info!("loading texture image: \x1b[35m{:?}", path.as_ref());

  let image = image::open(path).map_err(|e| LoadError::ConversionFailed(format!("{:?}", e)))?.to_rgba();
  let dim = image.dimensions();
  let raw: Vec<f32> = image.into_raw().into_iter().map(|x| {
    let y = x as f32 / 255.;

    if linear {
      y
    } else {
      y.powf(1. / 2.2)
    }
  }).collect();

  let tex = Texture::new(dim, 0, sampler).map_err(|e| LoadError::ConversionFailed(format!("{:?}", e)))?;
  tex.upload_raw(false, &raw);

  Ok(tex)
}

/// Save an RGBA image on disk.
pub fn save_rgba_texture<P>(texture: &Texture<Flat, Dim2, RGBA32F>, path: P) where P: AsRef<Path> {
  info!("saving texture image to: \x1b[35m{:?}", path.as_ref());

  let texels = texture.get_raw_texels();
  let (w, h) = texture.size();
  let mut output = Vec::with_capacity((w * h) as usize);

  for texel in &texels {
    output.push((texel * 255.) as u8);
  }

  let _ = image::save_buffer(path, &output, w, h, image::ColorType::RGBA(8));
}

pub struct TextureImage {
  pub texture: Texture<Flat, Dim2, RGBA32F>,
  sampler: Sampler,
  linear: bool,
}

impl Deref for TextureImage {
  type Target = Texture<Flat, Dim2, RGBA32F>;

  fn deref(&self) -> &Self::Target {
    &self.texture
  }
}

impl<'a> Load<'a> for TextureImage {
  type Args = (Sampler, bool);

  fn load<P>(path: P, _: &mut Cache<'a>, (sampler, linear): Self::Args) -> Result<Self> where P: AsRef<Path> {
    load_rgba_texture(path, &sampler, linear)
      .map(|tex| TextureImage {
        texture: tex,
        sampler: sampler,
        linear: linear
      })
  }
}

impl<'a> Reload<'a> for TextureImage {
  fn reload_args(&self) -> Self::Args {
    (self.sampler, self.linear)
  }
}
<commit_msg>Better export list for textures.<commit_after>use luminance::{Dim2, Flat, Sampler};
pub use luminance::{RGBA32F, Texture};
use image;
use std::ops::Deref;
use std::path::Path;

use resource::{Cache, Load, LoadError, Reload, Result};

/// Load an RGBA texture from an image at a path.
pub fn load_rgba_texture<P>(path: P, sampler: &Sampler, linear: bool) -> Result<Texture<Flat, Dim2, RGBA32F>> where P: AsRef<Path> {
  info!("loading texture image: \x1b[35m{:?}", path.as_ref());

  let image = image::open(path).map_err(|e| LoadError::ConversionFailed(format!("{:?}", e)))?.to_rgba();
  let dim = image.dimensions();
  let raw: Vec<f32> = image.into_raw().into_iter().map(|x| {
    let y = x as f32 / 255.;

    if linear {
      y
    } else {
      y.powf(1. / 2.2)
    }
  }).collect();

  let tex = Texture::new(dim, 0, sampler).map_err(|e| LoadError::ConversionFailed(format!("{:?}", e)))?;
  tex.upload_raw(false, &raw);

  Ok(tex)
}

/// Save an RGBA image on disk.
pub fn save_rgba_texture<P>(texture: &Texture<Flat, Dim2, RGBA32F>, path: P) where P: AsRef<Path> {
  info!("saving texture image to: \x1b[35m{:?}", path.as_ref());

  let texels = texture.get_raw_texels();
  let (w, h) = texture.size();
  let mut output = Vec::with_capacity((w * h) as usize);

  for texel in &texels {
    output.push((texel * 255.) as u8);
  }

  let _ = image::save_buffer(path, &output, w, h, image::ColorType::RGBA(8));
}

pub struct TextureImage {
  pub texture: Texture<Flat, Dim2, RGBA32F>,
  sampler: Sampler,
  linear: bool,
}

impl Deref for TextureImage {
  type Target = Texture<Flat, Dim2, RGBA32F>;

  fn deref(&self) -> &Self::Target {
    &self.texture
  }
}

impl<'a> Load<'a> for TextureImage {
  type Args = (Sampler, bool);

  fn load<P>(path: P, _: &mut Cache<'a>, (sampler, linear): Self::Args) -> Result<Self> where P: AsRef<Path> {
    load_rgba_texture(path, &sampler, linear)
      .map(|tex| TextureImage {
        texture: tex,
        sampler: sampler,
        linear: linear
      })
  }
}

impl<'a> Reload<'a> for TextureImage {
  fn reload_args(&self) -> Self::Args {
    (self.sampler, self.linear)
  }
}
<|endoftext|>


<commit_before><commit_msg>Use lowercase extension to determine image format<commit_after><|endoftext|>


<commit_before>use conrod::{Button,Positionable, Text, Sizeable,Widget,WidgetId,Canvas,Colorable,color,Labelable,Line,Circle};
use piston_window::Glyphs;
use ::{Backend,Graph,GraphNode,GraphEdge,Nid};

pub type Ui = ::conrod::Ui<Glyphs>;

pub trait UiNode: GraphNode {
    fn get_ui(&self) -> &UiBase;
    fn get_ui_mut(&mut self) -> &mut UiBase;
    fn build_ui(&mut self, ui: &mut Ui) -> bool {

        if self.get_ui().destroy { return false }

        let mut canvas_height = self.get_ui().height;
        let mut cl = "-"; //canvas label
        if self.get_ui().collapse {
            cl = "+";
            canvas_height = 20.0;
        }

        let ui_id_start: WidgetId = self.get_ui().get_id();

        let position = self.get_position().clone();

        let mut color = color::WHITE;
        if self.get_ui().select { color=color::RED; }

        //floating canvas where our node data resides
        Canvas::new()
            .floating(true)
            .title_bar(self.get_name())
            .xy([position[0], position[1]])
            .h(canvas_height)
            .w(self.get_ui().width)
            .color(color::BLUE)
            .label_color(color)
            .set(ui_id_start, ui);

        //build buttons in reverse order, to stay within canvas
        //start at top right, and head left from
        //close button
        Button::new()
            .top_right_of(ui_id_start) //todo: shift up ~5.0
            .label("x")
            .w_h(20.0,20.0)
            .react(|| self.get_ui_mut().destroy = true)
            .set(ui_id_start + 1, ui);

        //collapse
        Button::new()
            .left(5.0)
            .label(cl)
            .w_h(20.0,20.0)
            .react(|| self.get_ui_mut().toggle_collapse())
            .set(ui_id_start + 2, ui);

        //connector
        Button::new()
            .top_left_of(ui_id_start) //todo: shift up ~5.0
            .label("o")
            .w_h(20.0,20.0)
            .react(|| self.get_ui_mut().toggle_select())
            .set(ui_id_start + 3, ui);

        if !self.get_ui().collapse {
            Text::new("Node Data") // TODO: derive actual node data, and represent somehow
                .middle_of(ui_id_start)
                .set(ui_id_start + 4, ui);
        }

        self.get_ui().select
    }
}

#[derive(Debug,Clone,PartialEq)]
pub struct UiBase {
    ui_id: WidgetId,
    select: bool,
    collapse: bool,
    destroy: bool,
    width: f64,
    height: f64,
}

impl UiBase {
    pub fn default() -> UiBase {
        UiBase { ui_id: WidgetId(10000),
                 select: false,
                 collapse: false,
                 destroy: false,
                 width: 150.0,
                 height: 100.0,
        }
    }
    pub fn toggle_destroy(&mut self) { self.destroy = !self.destroy; }
    pub fn toggle_collapse(&mut self) { self.collapse = !self.collapse; }
    pub fn toggle_select(&mut self) { self.select = !self.select; }

    pub fn get_id(&self) -> WidgetId { self.ui_id }
    pub fn set_id(&mut self, id: WidgetId) { self.ui_id = id; }
}

pub trait UiGraph {
    fn render(&mut self, ui: &mut Ui);
}

impl<E:GraphEdge,N:UiNode> UiGraph for Graph<E,N> {
    fn render(&mut self, ui: &mut Ui) {
        let mut select: (Option<Nid>,Option<Nid>) = (None,None);
        let mut edges: Vec<(Nid,Vec<Nid>)> = vec!();

        self.with_nodes_mut(|n| {
            let is_select: bool = n.build_ui(ui);

            {
                let base = n.get_base();
                if is_select { //selected?
                    if select.0.is_some() {
                        if !select.1.is_some() {
                            select.1 = Some(base.get_id());
                        }
                    }
                    else { select.0 = Some(base.get_id()); }
                }

                let ev = base.get_edges();
                if ev.len() > 0 {
                    edges.push((base.get_id(),ev));
                }
            }

            if let Some(coord) = ui.xy_of(n.get_ui().get_id()) {
                n.set_position(coord);
            }
        });

        // build edges
        for (j,&(ref nid,ref ev)) in edges.iter().enumerate() {
            let n = self.get_node(&nid).unwrap();
            let id = n.get_ui().get_id().0 * 20; //allot 20 spaces per node
            let id = WidgetId(id + 1000); // place in 1k range
            let mut pos = *n.get_position();
            pos[1] = pos[1] + j as f64+12.;
            Circle::fill_with(10.,color::LIGHT_BLUE)
                .xy(pos)
                .set(id+1, ui);

            for (k,en) in ev.iter().enumerate() {
                let k = k + 1;
                if let Some(n2) = self.get_node(&en) {
                    Line::abs(*n.get_position(), *n2.get_position())
                        .set(id+2*k, ui);
                    Circle::fill_with(10.,color::ORANGE)
                        .xy(*n2.get_position())
                        .set(id+3*k, ui);
                }
            }
        }

        // build new edge
        match select {
            (Some(first),Some(second)) => {
                //clear node selection
                self.get_node_mut(&first).unwrap().get_ui_mut().select = false;
                self.get_node_mut(&second).unwrap().get_ui_mut().select = false;

                //todo: prompt for edge data!
                self.direct(&first,&second,E::default());
            },
            _ => (),
        }
    }
}
<commit_msg>proper draw ordering<commit_after>use conrod::{Button,Positionable, Text, Sizeable,Widget,WidgetId,Canvas,Colorable,color,Labelable,Line,Circle};
use piston_window::Glyphs;
use ::{Backend,Graph,GraphNode,GraphEdge,Nid};

pub type Ui = ::conrod::Ui<Glyphs>;

pub trait UiNode: GraphNode {
    fn get_ui(&self) -> &UiBase;
    fn get_ui_mut(&mut self) -> &mut UiBase;
    fn build_ui(&mut self, ui: &mut Ui) {

        if self.get_ui().destroy { return }

        let mut canvas_height = self.get_ui().height;
        let mut cl = "-"; //canvas label
        if self.get_ui().collapse {
            cl = "+";
            canvas_height = 20.0;
        }

        let ui_id_start: WidgetId = self.get_ui().get_id();

        let position = self.get_position().clone();

        let mut color = color::WHITE;
        if self.get_ui().select { color=color::RED; }

        //floating canvas where our node data resides
        Canvas::new()
            .floating(true)
            .title_bar(self.get_name())
            .xy([position[0], position[1]])
            .h(canvas_height)
            .w(self.get_ui().width)
            .color(color::BLUE)
            .label_color(color)
            .set(ui_id_start, ui);

        //build buttons in reverse order, to stay within canvas
        //start at top right, and head left from
        //close button
        Button::new()
            .top_right_of(ui_id_start) //todo: shift up ~5.0
            .label("x")
            .w_h(20.0,20.0)
            .react(|| self.get_ui_mut().destroy = true)
            .set(ui_id_start + 1, ui);

        //collapse
        Button::new()
            .left(5.0)
            .label(cl)
            .w_h(20.0,20.0)
            .react(|| self.get_ui_mut().toggle_collapse())
            .set(ui_id_start + 2, ui);

        //connector
        Button::new()
            .top_left_of(ui_id_start) //todo: shift up ~5.0
            .label("o")
            .w_h(20.0,20.0)
            .react(|| self.get_ui_mut().toggle_select())
            .set(ui_id_start + 3, ui);

        if !self.get_ui().collapse {
            Text::new("Node Data") // TODO: derive actual node data, and represent somehow
                .middle_of(ui_id_start)
                .set(ui_id_start + 4, ui);
        }
    }
}

#[derive(Debug,Clone,PartialEq)]
pub struct UiBase {
    ui_id: WidgetId,
    select: bool,
    collapse: bool,
    destroy: bool,
    width: f64,
    height: f64,
}

impl UiBase {
    pub fn default() -> UiBase {
        UiBase { ui_id: WidgetId(10000),
                 select: false,
                 collapse: false,
                 destroy: false,
                 width: 150.0,
                 height: 100.0,
        }
    }
    pub fn toggle_destroy(&mut self) { self.destroy = !self.destroy; }
    pub fn toggle_collapse(&mut self) { self.collapse = !self.collapse; }
    pub fn toggle_select(&mut self) { self.select = !self.select; }

    pub fn get_id(&self) -> WidgetId { self.ui_id }
    pub fn set_id(&mut self, id: WidgetId) { self.ui_id = id; }
}

pub trait UiGraph {
    fn render(&mut self, ui: &mut Ui);
}

impl<E:GraphEdge,N:UiNode> UiGraph for Graph<E,N> {
    fn render(&mut self, ui: &mut Ui) {
        let mut select: (Option<Nid>,Option<Nid>) = (None,None);
        let mut edges: Vec<(Nid,Vec<Nid>)> = vec!();

        self.with_nodes_mut(|n| {
            let is_select = n.get_ui().select;

            {
                let base = n.get_base();
                if is_select { //selected?
                    if select.0.is_some() {
                        if !select.1.is_some() {
                            select.1 = Some(base.get_id());
                        }
                    }
                    else { select.0 = Some(base.get_id()); }
                }

                let ev = base.get_edges();
                if ev.len() > 0 {
                    edges.push((base.get_id(),ev));
                }
            }

            if let Some(coord) = ui.xy_of(n.get_ui().get_id()) {
                n.set_position(coord);
            }
        });

        let socket_id_out = 1;
        let line_id = 2;
        let socket_id_in = 3;

        // build edges
        for &(ref nid,ref ev) in edges.iter() {
            let n = self.get_node(&nid).unwrap();
            let id = n.get_ui().get_id().0 * 20; //allot 20 spaces per node
            let id = WidgetId(id + 1000); // place in 1k range

            for (k,en) in ev.iter().enumerate() {
                let k = k + 1;
                if let Some(n2) = self.get_node(&en) {
                    Line::abs(*n.get_position(), *n2.get_position())
                        .set(id+line_id*k, ui);
                }
            }
        }

        self.with_nodes_mut(|n| {
            n.build_ui(ui);
        });

        // build sockets
        // NOTE: this duplication from 'build_edges' should be fixed
        // only way I could figure out proper draw order
        for (j,&(ref nid,ref ev)) in edges.iter().enumerate() {
            let n = self.get_node(&nid).unwrap();
            let id = n.get_ui().get_id().0 * 20; //allot 20 spaces per node
            let id = WidgetId(id + 1000); // place in 1k range
            let mut pos = *n.get_position();
            pos[1] = pos[1] + j as f64+12.;
            Circle::fill_with(10.,color::LIGHT_BLUE)
                .xy(pos)
                .set(id+socket_id_out, ui);

            for (k,en) in ev.iter().enumerate() {
                let k = k + 1;
                if let Some(n2) = self.get_node(&en) {
                    Circle::fill_with(10.,color::ORANGE)
                        .xy(*n2.get_position())
                        .set(id+socket_id_in*k, ui);
                }
            }
        }

        // build new edge
        match select {
            (Some(first),Some(second)) => {
                //clear node selection
                self.get_node_mut(&first).unwrap().get_ui_mut().select = false;
                self.get_node_mut(&second).unwrap().get_ui_mut().select = false;

                //todo: prompt for edge data!
                self.direct(&first,&second,E::default());
            },
            _ => (),
        }
    }
}
<|endoftext|>


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

use conduit::{Request, Response};
use conduit_router::RequestParams;
use pg::GenericConnection;
use pg::rows::Row;
use rustc_serialize::json;
use semver;
use time::Duration;
use time::Timespec;
use url;

use {Model, Crate};
use app::RequestApp;
use db::RequestTransaction;
use dependency::{Dependency, EncodableDependency, Kind};
use download::{VersionDownload, EncodableVersionDownload};
use git;
use upload;
use user::RequestUser;
use owner::{rights, Rights};
use util::{RequestUtils, CargoResult, ChainError, internal, human};

#[derive(Clone)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: semver::Version,
    pub updated_at: Timespec,
    pub created_at: Timespec,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

pub struct Author {
    pub name: String
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct EncodableVersion {
    pub id: i32,
    pub krate: String,
    pub num: String,
    pub dl_path: String,
    pub updated_at: String,
    pub created_at: String,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
    pub links: VersionLinks,
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct VersionLinks {
    pub dependencies: String,
    pub version_downloads: String,
    pub authors: String,
}

impl Version {
    pub fn find_by_num(conn: &GenericConnection,
                       crate_id: i32,
                       num: &semver::Version)
                       -> CargoResult<Option<Version>> {
        let num = num.to_string();
        let stmt = conn.prepare("SELECT * FROM versions \
                                      WHERE crate_id = $1 AND num = $2")?;
        let rows = stmt.query(&[&crate_id, &num])?;
        Ok(rows.iter().next().map(|r| Model::from_row(&r)))
    }

    pub fn insert(conn: &GenericConnection,
                  crate_id: i32,
                  num: &semver::Version,
                  features: &HashMap<String, Vec<String>>,
                  authors: &[String])
                  -> CargoResult<Version> {
        let num = num.to_string();
        let features = json::encode(features).unwrap();
        let stmt = conn.prepare("INSERT INTO versions \
                                      (crate_id, num, features) \
                                      VALUES ($1, $2, $3) \
                                      RETURNING *")?;
        let rows = stmt.query(&[&crate_id, &num, &features])?;
        let ret: Version = Model::from_row(&rows.iter().next().chain_error(|| {
            internal("no version returned")
        })?);
        for author in authors.iter() {
            ret.add_author(conn, &author)?;
        }
        Ok(ret)
    }

    pub fn valid(version: &str) -> bool {
        semver::Version::parse(version).is_ok()
    }

    pub fn encodable(self, crate_name: &str) -> EncodableVersion {
        let Version { id, crate_id: _, num, updated_at, created_at,
                      downloads, features, yanked } = self;
        let num = num.to_string();
        EncodableVersion {
            dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num),
            num: num.clone(),
            id: id,
            krate: crate_name.to_string(),
            updated_at: ::encode_time(updated_at),
            created_at: ::encode_time(created_at),
            downloads: downloads,
            features: features,
            yanked: yanked,
            links: VersionLinks {
                dependencies: format!("/api/v1/crates/{}/{}/dependencies",
                                      crate_name, num),
                version_downloads: format!("/api/v1/crates/{}/{}/downloads",
                                           crate_name, num),
                authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num),
            },
        }
    }

    /// Add a dependency to this version, returning both the dependency and the
    /// crate that the dependency points to
    pub fn add_dependency(&mut self,
                          conn: &GenericConnection,
                          dep: &upload::CrateDependency)
                          -> CargoResult<(Dependency, Crate)> {
        let name = &dep.name;
        let krate = Crate::find_by_name(conn, name).map_err(|_| {
            human(format!("no known crate named `{}`", &**name))
        })?;
        if dep.version_req.0 == semver::VersionReq::parse("*").unwrap() {
            return Err(human(format!("wildcard (`*`) dependency constraints are not allowed \
                                      on crates.io. See http://doc.crates.io/faq.html#can-\
                                      libraries-use--as-a-version-for-their-dependencies for more \
                                      information")));
        }
        let features: Vec<String> = dep.features.iter().map(|s| {
            s[..].to_string()
        }).collect();
        let dep = Dependency::insert(conn, self.id, krate.id,
                                     &*dep.version_req,
                                     dep.kind.unwrap_or(Kind::Normal),
                                     dep.optional,
                                     dep.default_features,
                                     &features,
                                     &dep.target)?;
        Ok((dep, krate))
    }

    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &GenericConnection)
                        -> CargoResult<Vec<(Dependency, String)>> {
        let stmt = conn.prepare("SELECT dependencies.*,
                                             crates.name AS crate_name
                                      FROM dependencies
                                      LEFT JOIN crates
                                        ON crates.id = dependencies.crate_id
                                      WHERE dependencies.version_id = $1
                                      ORDER BY optional, name")?;
        let rows = stmt.query(&[&self.id])?;
        Ok(rows.iter().map(|r| {
            (Model::from_row(&r), r.get("crate_name"))
        }).collect())
    }

    pub fn authors(&self, conn: &GenericConnection) -> CargoResult<Vec<Author>> {
        let stmt = conn.prepare("SELECT * FROM version_authors
                                       WHERE version_id = $1
                                       ORDER BY name ASC")?;
        let rows = stmt.query(&[&self.id])?;
        Ok(rows.into_iter().map(|row| {
            Author { name: row.get("name") }
        }).collect())
    }

    pub fn add_author(&self,
                      conn: &GenericConnection,
                      name: &str) -> CargoResult<()> {
        conn.execute("INSERT INTO version_authors (version_id, name)
                           VALUES ($1, $2)", &[&self.id, &name])?;
        Ok(())
    }

    pub fn yank(&self, conn: &GenericConnection, yanked: bool) -> CargoResult<()> {
        conn.execute("UPDATE versions SET yanked = $1 WHERE id = $2",
                     &[&yanked, &self.id])?;
        Ok(())
    }
}

impl Model for Version {
    fn from_row(row: &Row) -> Version {
        let num: String = row.get("num");
        let features: Option<String> = row.get("features");
        let features = features.map(|s| {
            json::decode(&s).unwrap()
        }).unwrap_or_else(|| HashMap::new());
        Version {
            id: row.get("id"),
            crate_id: row.get("crate_id"),
            num: semver::Version::parse(&num).unwrap(),
            updated_at: row.get("updated_at"),
            created_at: row.get("created_at"),
            downloads: row.get("downloads"),
            features: features,
            yanked: row.get("yanked"),
        }
    }
    fn table_name(_: Option<Version>) -> &'static str { "versions" }
}

/// Handles the `GET /versions` route.
pub fn index(req: &mut Request) -> CargoResult<Response> {
    let conn = req.tx()?;

    // Extract all ids requested.
    let query = url::form_urlencoded::parse(req.query_string().unwrap_or("")
                                               .as_bytes());
    let ids = query.filter_map(|(ref a, ref b)| {
        if *a == "ids[]" {
            b.parse().ok()
        } else {
            None
        }
    }).collect::<Vec<i32>>();

    // Load all versions
    //
    // TODO: can rust-postgres do this for us?
    let mut versions = Vec::new();
    if ids.len() > 0 {
        let stmt = conn.prepare("\
            SELECT versions.*, crates.name AS crate_name
              FROM versions
            LEFT JOIN crates ON crates.id = versions.crate_id
            WHERE versions.id = ANY($1)
        ")?;
        for row in stmt.query(&[&ids])?.iter() {
            let v: Version = Model::from_row(&row);
            let crate_name: String = row.get("crate_name");
            versions.push(v.encodable(&crate_name));
        }
    }

    #[derive(RustcEncodable)]
    struct R { versions: Vec<EncodableVersion> }
    Ok(req.json(&R { versions: versions }))
}

/// Handles the `GET /versions/:version_id` route.
pub fn show(req: &mut Request) -> CargoResult<Response> {
    let (version, krate) = match req.params().find("crate_id") {
        Some(..) => version_and_crate(req)?,
        None => {
            let id = &req.params()["version_id"];
            let id = id.parse().unwrap_or(0);
            let conn = req.tx()?;
            let version = Version::find(&*conn, id)?;
            let krate = Crate::find(&*conn, version.crate_id)?;
            (version, krate)
        }
    };

    #[derive(RustcEncodable)]
    struct R { version: EncodableVersion }
    Ok(req.json(&R { version: version.encodable(&krate.name) }))
}

fn version_and_crate(req: &mut Request) -> CargoResult<(Version, Crate)> {
    let crate_name = &req.params()["crate_id"];
    let semver = &req.params()["version"];
    let semver = semver::Version::parse(semver).map_err(|_| {
        human(format!("invalid semver: {}", semver))
    })?;
    let tx = req.tx()?;
    let krate = Crate::find_by_name(tx, crate_name)?;
    let version = Version::find_by_num(tx, krate.id, &semver)?;
    let version = version.chain_error(|| {
        human(format!("crate `{}` does not have a version `{}`",
                      crate_name, semver))
    })?;
    Ok((version, krate))
}

/// Handles the `GET /crates/:crate_id/:version/dependencies` route.
pub fn dependencies(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;
    let tx = req.tx()?;
    let deps = version.dependencies(tx)?;
    let deps = deps.into_iter().map(|(dep, crate_name)| {
        dep.encodable(&crate_name, None)
    }).collect();

    #[derive(RustcEncodable)]
    struct R { dependencies: Vec<EncodableDependency> }
    Ok(req.json(&R{ dependencies: deps }))
}

/// Handles the `GET /crates/:crate_id/:version/downloads` route.
pub fn downloads(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;

    let tx = req.tx()?;
    let cutoff_date = ::now() + Duration::days(-90);
    let stmt = tx.prepare("SELECT * FROM version_downloads
                                WHERE date > $1 AND version_id = $2
                                ORDER BY date ASC")?;
    let mut downloads = Vec::new();
    for row in stmt.query(&[&cutoff_date, &version.id])?.iter() {
        let download: VersionDownload = Model::from_row(&row);
        downloads.push(download.encodable());
    }

    #[derive(RustcEncodable)]
    struct R { version_downloads: Vec<EncodableVersionDownload> }
    Ok(req.json(&R{ version_downloads: downloads }))
}

/// Handles the `GET /crates/:crate_id/:version/authors` route.
pub fn authors(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;
    let tx = req.tx()?;
    let names = version.authors(tx)?.into_iter().map(|a| a.name).collect();

    // It was imagined that we wold associate authors with users.
    // This was never implemented. This complicated return struct
    // is all that is left, hear for backwards compatibility.
    #[derive(RustcEncodable)]
    struct R { users: Vec<::user::EncodableUser>, meta: Meta }
    #[derive(RustcEncodable)]
    struct Meta { names: Vec<String> }
    Ok(req.json(&R{ users: vec![], meta: Meta { names: names } }))
}

/// Handles the `DELETE /crates/:crate_id/:version/yank` route.
pub fn yank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, true)
}

/// Handles the `PUT /crates/:crate_id/:version/unyank` route.
pub fn unyank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, false)
}

fn modify_yank(req: &mut Request, yanked: bool) -> CargoResult<Response> {
    let (version, krate) = version_and_crate(req)?;
    let user = req.user()?;
    let tx = req.tx()?;
    let owners = krate.owners(tx)?;
    if rights(req.app(), &owners, &user)? < Rights::Publish {
        return Err(human("must already be an owner to yank or unyank"))
    }

    if version.yanked != yanked {
        version.yank(tx, yanked)?;
        git::yank(&**req.app(), &krate.name, &version.num, yanked)?;
    }

    #[derive(RustcEncodable)]
    struct R { ok: bool }
    Ok(req.json(&R{ ok: true }))
}
<commit_msg>Remove a mut vec<commit_after>use std::collections::HashMap;

use conduit::{Request, Response};
use conduit_router::RequestParams;
use pg::GenericConnection;
use pg::rows::Row;
use rustc_serialize::json;
use semver;
use time::Duration;
use time::Timespec;
use url;

use {Model, Crate};
use app::RequestApp;
use db::RequestTransaction;
use dependency::{Dependency, EncodableDependency, Kind};
use download::{VersionDownload, EncodableVersionDownload};
use git;
use upload;
use user::RequestUser;
use owner::{rights, Rights};
use util::{RequestUtils, CargoResult, ChainError, internal, human};

#[derive(Clone)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: semver::Version,
    pub updated_at: Timespec,
    pub created_at: Timespec,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

pub struct Author {
    pub name: String
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct EncodableVersion {
    pub id: i32,
    pub krate: String,
    pub num: String,
    pub dl_path: String,
    pub updated_at: String,
    pub created_at: String,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
    pub links: VersionLinks,
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct VersionLinks {
    pub dependencies: String,
    pub version_downloads: String,
    pub authors: String,
}

impl Version {
    pub fn find_by_num(conn: &GenericConnection,
                       crate_id: i32,
                       num: &semver::Version)
                       -> CargoResult<Option<Version>> {
        let num = num.to_string();
        let stmt = conn.prepare("SELECT * FROM versions \
                                      WHERE crate_id = $1 AND num = $2")?;
        let rows = stmt.query(&[&crate_id, &num])?;
        Ok(rows.iter().next().map(|r| Model::from_row(&r)))
    }

    pub fn insert(conn: &GenericConnection,
                  crate_id: i32,
                  num: &semver::Version,
                  features: &HashMap<String, Vec<String>>,
                  authors: &[String])
                  -> CargoResult<Version> {
        let num = num.to_string();
        let features = json::encode(features).unwrap();
        let stmt = conn.prepare("INSERT INTO versions \
                                      (crate_id, num, features) \
                                      VALUES ($1, $2, $3) \
                                      RETURNING *")?;
        let rows = stmt.query(&[&crate_id, &num, &features])?;
        let ret: Version = Model::from_row(&rows.iter().next().chain_error(|| {
            internal("no version returned")
        })?);
        for author in authors.iter() {
            ret.add_author(conn, &author)?;
        }
        Ok(ret)
    }

    pub fn valid(version: &str) -> bool {
        semver::Version::parse(version).is_ok()
    }

    pub fn encodable(self, crate_name: &str) -> EncodableVersion {
        let Version { id, crate_id: _, num, updated_at, created_at,
                      downloads, features, yanked } = self;
        let num = num.to_string();
        EncodableVersion {
            dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num),
            num: num.clone(),
            id: id,
            krate: crate_name.to_string(),
            updated_at: ::encode_time(updated_at),
            created_at: ::encode_time(created_at),
            downloads: downloads,
            features: features,
            yanked: yanked,
            links: VersionLinks {
                dependencies: format!("/api/v1/crates/{}/{}/dependencies",
                                      crate_name, num),
                version_downloads: format!("/api/v1/crates/{}/{}/downloads",
                                           crate_name, num),
                authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num),
            },
        }
    }

    /// Add a dependency to this version, returning both the dependency and the
    /// crate that the dependency points to
    pub fn add_dependency(&mut self,
                          conn: &GenericConnection,
                          dep: &upload::CrateDependency)
                          -> CargoResult<(Dependency, Crate)> {
        let name = &dep.name;
        let krate = Crate::find_by_name(conn, name).map_err(|_| {
            human(format!("no known crate named `{}`", &**name))
        })?;
        if dep.version_req.0 == semver::VersionReq::parse("*").unwrap() {
            return Err(human(format!("wildcard (`*`) dependency constraints are not allowed \
                                      on crates.io. See http://doc.crates.io/faq.html#can-\
                                      libraries-use--as-a-version-for-their-dependencies for more \
                                      information")));
        }
        let features: Vec<String> = dep.features.iter().map(|s| {
            s[..].to_string()
        }).collect();
        let dep = Dependency::insert(conn, self.id, krate.id,
                                     &*dep.version_req,
                                     dep.kind.unwrap_or(Kind::Normal),
                                     dep.optional,
                                     dep.default_features,
                                     &features,
                                     &dep.target)?;
        Ok((dep, krate))
    }

    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &GenericConnection)
                        -> CargoResult<Vec<(Dependency, String)>> {
        let stmt = conn.prepare("SELECT dependencies.*,
                                             crates.name AS crate_name
                                      FROM dependencies
                                      LEFT JOIN crates
                                        ON crates.id = dependencies.crate_id
                                      WHERE dependencies.version_id = $1
                                      ORDER BY optional, name")?;
        let rows = stmt.query(&[&self.id])?;
        Ok(rows.iter().map(|r| {
            (Model::from_row(&r), r.get("crate_name"))
        }).collect())
    }

    pub fn authors(&self, conn: &GenericConnection) -> CargoResult<Vec<Author>> {
        let stmt = conn.prepare("SELECT * FROM version_authors
                                       WHERE version_id = $1
                                       ORDER BY name ASC")?;
        let rows = stmt.query(&[&self.id])?;
        Ok(rows.into_iter().map(|row| {
            Author { name: row.get("name") }
        }).collect())
    }

    pub fn add_author(&self,
                      conn: &GenericConnection,
                      name: &str) -> CargoResult<()> {
        conn.execute("INSERT INTO version_authors (version_id, name)
                           VALUES ($1, $2)", &[&self.id, &name])?;
        Ok(())
    }

    pub fn yank(&self, conn: &GenericConnection, yanked: bool) -> CargoResult<()> {
        conn.execute("UPDATE versions SET yanked = $1 WHERE id = $2",
                     &[&yanked, &self.id])?;
        Ok(())
    }
}

impl Model for Version {
    fn from_row(row: &Row) -> Version {
        let num: String = row.get("num");
        let features: Option<String> = row.get("features");
        let features = features.map(|s| {
            json::decode(&s).unwrap()
        }).unwrap_or_else(|| HashMap::new());
        Version {
            id: row.get("id"),
            crate_id: row.get("crate_id"),
            num: semver::Version::parse(&num).unwrap(),
            updated_at: row.get("updated_at"),
            created_at: row.get("created_at"),
            downloads: row.get("downloads"),
            features: features,
            yanked: row.get("yanked"),
        }
    }
    fn table_name(_: Option<Version>) -> &'static str { "versions" }
}

/// Handles the `GET /versions` route.
pub fn index(req: &mut Request) -> CargoResult<Response> {
    let conn = req.tx()?;

    // Extract all ids requested.
    let query = url::form_urlencoded::parse(req.query_string().unwrap_or("")
                                               .as_bytes());
    let ids = query.filter_map(|(ref a, ref b)| {
        if *a == "ids[]" {
            b.parse().ok()
        } else {
            None
        }
    }).collect::<Vec<i32>>();

    // Load all versions
    //
    // TODO: can rust-postgres do this for us?
    let mut versions = Vec::new();
    if ids.len() > 0 {
        let stmt = conn.prepare("\
            SELECT versions.*, crates.name AS crate_name
              FROM versions
            LEFT JOIN crates ON crates.id = versions.crate_id
            WHERE versions.id = ANY($1)
        ")?;
        for row in stmt.query(&[&ids])?.iter() {
            let v: Version = Model::from_row(&row);
            let crate_name: String = row.get("crate_name");
            versions.push(v.encodable(&crate_name));
        }
    }

    #[derive(RustcEncodable)]
    struct R { versions: Vec<EncodableVersion> }
    Ok(req.json(&R { versions: versions }))
}

/// Handles the `GET /versions/:version_id` route.
pub fn show(req: &mut Request) -> CargoResult<Response> {
    let (version, krate) = match req.params().find("crate_id") {
        Some(..) => version_and_crate(req)?,
        None => {
            let id = &req.params()["version_id"];
            let id = id.parse().unwrap_or(0);
            let conn = req.tx()?;
            let version = Version::find(&*conn, id)?;
            let krate = Crate::find(&*conn, version.crate_id)?;
            (version, krate)
        }
    };

    #[derive(RustcEncodable)]
    struct R { version: EncodableVersion }
    Ok(req.json(&R { version: version.encodable(&krate.name) }))
}

fn version_and_crate(req: &mut Request) -> CargoResult<(Version, Crate)> {
    let crate_name = &req.params()["crate_id"];
    let semver = &req.params()["version"];
    let semver = semver::Version::parse(semver).map_err(|_| {
        human(format!("invalid semver: {}", semver))
    })?;
    let tx = req.tx()?;
    let krate = Crate::find_by_name(tx, crate_name)?;
    let version = Version::find_by_num(tx, krate.id, &semver)?;
    let version = version.chain_error(|| {
        human(format!("crate `{}` does not have a version `{}`",
                      crate_name, semver))
    })?;
    Ok((version, krate))
}

/// Handles the `GET /crates/:crate_id/:version/dependencies` route.
pub fn dependencies(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;
    let tx = req.tx()?;
    let deps = version.dependencies(tx)?;
    let deps = deps.into_iter().map(|(dep, crate_name)| {
        dep.encodable(&crate_name, None)
    }).collect();

    #[derive(RustcEncodable)]
    struct R { dependencies: Vec<EncodableDependency> }
    Ok(req.json(&R{ dependencies: deps }))
}

/// Handles the `GET /crates/:crate_id/:version/downloads` route.
pub fn downloads(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;

    let tx = req.tx()?;
    let cutoff_date = ::now() + Duration::days(-90);
    let stmt = tx.prepare("SELECT * FROM version_downloads
                                WHERE date > $1 AND version_id = $2
                                ORDER BY date ASC")?;
    let downloads = stmt.query(&[&cutoff_date, &version.id])?.iter().map(|row| {
        VersionDownload::from_row(&row).encodable()
    }).collect();

    #[derive(RustcEncodable)]
    struct R { version_downloads: Vec<EncodableVersionDownload> }
    Ok(req.json(&R{ version_downloads: downloads }))
}

/// Handles the `GET /crates/:crate_id/:version/authors` route.
pub fn authors(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;
    let tx = req.tx()?;
    let names = version.authors(tx)?.into_iter().map(|a| a.name).collect();

    // It was imagined that we wold associate authors with users.
    // This was never implemented. This complicated return struct
    // is all that is left, hear for backwards compatibility.
    #[derive(RustcEncodable)]
    struct R { users: Vec<::user::EncodableUser>, meta: Meta }
    #[derive(RustcEncodable)]
    struct Meta { names: Vec<String> }
    Ok(req.json(&R{ users: vec![], meta: Meta { names: names } }))
}

/// Handles the `DELETE /crates/:crate_id/:version/yank` route.
pub fn yank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, true)
}

/// Handles the `PUT /crates/:crate_id/:version/unyank` route.
pub fn unyank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, false)
}

fn modify_yank(req: &mut Request, yanked: bool) -> CargoResult<Response> {
    let (version, krate) = version_and_crate(req)?;
    let user = req.user()?;
    let tx = req.tx()?;
    let owners = krate.owners(tx)?;
    if rights(req.app(), &owners, &user)? < Rights::Publish {
        return Err(human("must already be an owner to yank or unyank"))
    }

    if version.yanked != yanked {
        version.yank(tx, yanked)?;
        git::yank(&**req.app(), &krate.name, &version.num, yanked)?;
    }

    #[derive(RustcEncodable)]
    struct R { ok: bool }
    Ok(req.json(&R{ ok: true }))
}
<|endoftext|>


<commit_before>#![crate_type = "rlib"]

//! Macro to create a "view box", a box containing immutable data
//! plus a "view" struct that can have interior references into
//! the data.  The view box can be moved around as an atomic unit.
//! I haven't completely convinced myself this is memory safe yet.
//! In particular, I need to make sure dangling pointers can't be
//! observed if the view struct implements Drop
#![feature(macro_rules, globs)]

#[macro_export]
macro_rules! viewbox(
    ($(#[$attr:meta])* struct $name:ident<$d:ty, $v:ident>;) => (
        $(#[$attr])*
        pub struct $name {
            data: Box<$d>,
            view: $v<'static>
        }

        #[allow(dead_code)]
        impl $name {
            pub fn new(data: $d, f: <'a>|&'a mut $d| -> $v<'a>) -> $name {
                let mut d = box data;
                let v = unsafe { ::std::mem::transmute(f(&mut *d)) };

                $name {
                    data: d,
                    view: v
                }
            }

            pub fn new_result<E>(data: $d,
                                 f: <'a>|&'a mut $d|
                                    -> ::std::result::Result<$v<'a>,E>)
                                 -> ::std::result::Result<$name,($d,E)> {
                let mut d = box data;
                match f(&mut *d).map(|v| unsafe { ::std::mem::transmute(v) }) {
                    Ok(v) => {
                        Ok($name {
                            data: d,
                            view: v
                        })
                    },
                    Err(e) => Err((*d,e))
                }
            }

            pub fn unwrap(self)-> $d {
                let $name { data: box data, .. } = self;
                data
            }

            pub fn view<'a>(&'a self) -> &'a $v<'a> {
                unsafe { ::std::mem::transmute(&self.view) }
            }

            pub fn mut_view<'a>(&'a mut self) -> &'a mut $v<'a> {
                unsafe { ::std::mem::transmute(&mut self.view) }
            }
        }
    )
)

#[cfg(test)]
mod test {
    // Test data structure
    #[deriving(PartialEq,Show)]
    struct TestData {
        foo: i32,
        bar: String
    }

    // View structure that has references into the boxed data
    struct TestView<'a> {
        x: &'a i32,
        y: &'a str
    }

    // Create TestBox which combines TestData and TestView
    viewbox! {
        struct TestBox<TestData,TestView>;
    }

    // Mutable view into string
    struct MutView<'a> {
        x: &'a mut String
    }

    // MutBox combines TestData and MutView
    viewbox! {
        struct MutBox<TestData, MutView>;
    }

    #[test]
    fn basic() {
        // Create some data
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        // Move it into box, creating a view with interior references
        let v = TestBox::new(t, |d| TestView { x: &d.foo, y: d.bar.as_slice() });

        // We can access the boxed data via the view
        assert_eq!(v.view().x, &42i32);
        assert_eq!(v.view().y, "Hello");
        // We can unwrap the view to get the data back
        let t = v.unwrap();
        assert_eq!(t.foo, 42i32);
        assert_eq!(t.bar, "Hello".to_string());
    }

    #[test]
    fn mutation() {
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        let mut v = MutBox::new(t, |d| MutView { x: &mut d.bar });

        *v.mut_view().x = "Goodbye".to_string();
        let t = v.unwrap();
        assert_eq!(t.bar, "Goodbye".to_string());
    }

    #[test]
    fn error() {
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        let v = MutBox::new_result(t, |_| Err("Nope")).err().unwrap();
        assert_eq!(v, (TestData { foo: 42, bar: "Hello".to_string() }, "Nope"))
    }
}
<commit_msg>Disable passing through attributes<commit_after>#![crate_type = "rlib"]

//! Macro to create a "view box", a box containing immutable data
//! plus a "view" struct that can have interior references into
//! the data.  The view box can be moved around as an atomic unit.
//! I haven't completely convinced myself this is memory safe yet.
//! In particular, I need to make sure dangling pointers can't be
//! observed if the view struct implements Drop
#![feature(macro_rules, globs)]

#[macro_export]
macro_rules! viewbox(
    (struct $name:ident<$d:ty, $v:ident>;) => (
        pub struct $name {
            data: Box<$d>,
            view: $v<'static>
        }

        #[allow(dead_code)]
        impl $name {
            pub fn new(data: $d, f: <'a>|&'a mut $d| -> $v<'a>) -> $name {
                let mut d = box data;
                let v = unsafe { ::std::mem::transmute(f(&mut *d)) };

                $name { data: d, view: v }
            }

            pub fn new_result<E>(data: $d,
                                 f: <'a>|&'a mut $d|
                                    -> ::std::result::Result<$v<'a>,E>)
                                 -> ::std::result::Result<$name,($d,E)> {
                let mut d = box data;
                match f(&mut *d).map(|v| unsafe { ::std::mem::transmute(v) }) {
                    Ok(v) => Ok($name { data: d, view: v }),
                    Err(e) => Err((*d,e))
                }
            }

            pub fn unwrap(self)-> $d {
                let $name { data: box data, .. } = self;
                data
            }

            pub fn view<'a>(&'a self) -> &'a $v<'a> {
                unsafe { ::std::mem::transmute(&self.view) }
            }

            pub fn mut_view<'a>(&'a mut self) -> &'a mut $v<'a> {
                unsafe { ::std::mem::transmute(&mut self.view) }
            }
        }
    );
    (#[deriving(PartialEq $(,$derive:ident)*)] struct $name:ident<$d:ty, $v:ident>;) => (
        impl ::std::cmp::PartialEq for $name {
            fn eq(&self, other: &$name) -> bool { self.view() == other.view(); }
        }
        viewbox!(struct $name<$d,$v>;)
    );
    (#[deriving(Show $(,$derive:ident)*)] struct $name:ident<$d:ty, $v:ident>;) => (
        impl ::std::fmt::Show for $name {
            fn fmt(&self, fmt: &mut ::std::fmt::Formatter)
                   -> ::std::result::Result<(), ::std::fmt::FormatError> {
                self.view().fmt(fmt)
            }
        }
        viewbox!(struct $name<$d,$v>;)
    );
    (#[deriving()] struct $name:ident<$d:ty, $v:ident>;) => (
        viewbox!(struct $name<$d,$v>;)
    );
)

#[cfg(test)]
mod test {
    // Test data structure
    #[deriving(PartialEq,Show)]
    struct TestData {
        foo: i32,
        bar: String
    }

    // View structure that has references into the boxed data
    struct TestView<'a> {
        x: &'a i32,
        y: &'a str
    }

    // Create TestBox which combines TestData and TestView
    viewbox! {
        struct TestBox<TestData,TestView>;
    }

    // Mutable view into string
    struct MutView<'a> {
        x: &'a mut String
    }

    // MutBox combines TestData and MutView
    viewbox! {
        struct MutBox<TestData, MutView>;
    }

    #[test]
    fn basic() {
        // Create some data
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        // Move it into box, creating a view with interior references
        let v = TestBox::new(t, |d| TestView { x: &d.foo, y: d.bar.as_slice() });

        // We can access the boxed data via the view
        assert_eq!(v.view().x, &42i32);
        assert_eq!(v.view().y, "Hello");
        // We can unwrap the view to get the data back
        let t = v.unwrap();
        assert_eq!(t.foo, 42i32);
        assert_eq!(t.bar, "Hello".to_string());
    }

    #[test]
    fn mutation() {
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        let mut v = MutBox::new(t, |d| MutView { x: &mut d.bar });

        *v.mut_view().x = "Goodbye".to_string();
        let t = v.unwrap();
        assert_eq!(t.bar, "Goodbye".to_string());
    }

    #[test]
    fn error() {
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        let v = MutBox::new_result(t, |_| Err("Nope")).err().unwrap();
        assert_eq!(v, (TestData { foo: 42, bar: "Hello".to_string() }, "Nope"))
    }
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use aarch64_esr_decoder::{decode, parse_number, DecodeError, FieldInfo};
use std::ops::Deref;
use wasm_bindgen::prelude::*;
use web_sys::{Document, Element};

#[wasm_bindgen]
pub fn init() {
    #[cfg(feature = "console_error_panic_hook")]
    console_error_panic_hook::set_once();
}

#[wasm_bindgen]
pub fn decode_esr(esr: &str) -> Result<(), JsValue> {
    match parse_number(esr) {
        Ok(esr) => {
            let decoded = decode(esr);
            show_decoded(esr, decoded)?;
        }
        Err(_) => show_error("Invalid ESR"),
    }
    Ok(())
}

fn show_error(error: &str) {
    let document = web_sys::window()
        .expect("Couldn't find window")
        .document()
        .expect("Couldn't find document");
    let error_element = document
        .get_element_by_id("error")
        .expect("Couldn't find error element");
    let table = document
        .get_element_by_id("result_table")
        .expect("Couldn't find result table");
    // Clear output table.
    table.set_inner_html("");
    error_element.set_text_content(Some(error));
}

fn show_decoded(esr: u64, decoded: Result<Vec<FieldInfo>, DecodeError>) -> Result<(), JsValue> {
    let document = web_sys::window()
        .expect("Couldn't find window")
        .document()
        .expect("Couldn't find document");
    let error_element = document
        .get_element_by_id("error")
        .expect("Couldn't find error element");
    let table = document
        .get_element_by_id("result_table")
        .expect("Couldn't find result table");
    // Remove existing contents.
    error_element.set_inner_html("");
    table.set_inner_html("");

    // ESR in hexadecimal
    let row = document.create_element("tr")?;
    row.set_attribute("class", "value")?;
    let esr_hex = format!("{:016x}", esr);
    for digit in esr_hex.chars() {
        let cell = make_cell(&document, Some(&digit.to_string()), 4)?;
        row.append_child(&cell)?;
    }
    table.append_child(&row)?;

    // ESR in binary
    let row = document.create_element("tr")?;
    row.set_attribute("class", "value")?;
    for i in (0..u64::BITS).rev() {
        let bit = esr & (1 << i) != 0;
        let cell = make_cell(&document, Some(if bit { "1" } else { "0" }), 1)?;
        row.append_child(&cell)?;
    }
    table.append_child(&row)?;

    match decoded {
        Ok(fields) => {
            // Top-level field names and values
            let row = document.create_element("tr")?;
            row.set_attribute("class", "name")?;
            let mut last = 64;
            add_field_cells(&document, &row, &fields, &mut last, |field| {
                Some(field.to_string())
            })?;
            table.append_child(&row)?;

            // Top-level field descriptions
            let row = document.create_element("tr")?;
            row.set_attribute("class", "description")?;
            let mut last = 64;
            add_field_cells(&document, &row, &fields, &mut last, |field| {
                field.description.clone()
            })?;
            table.append_child(&row)?;

            // Second level field names and values
            let row = document.create_element("tr")?;
            row.set_attribute("class", "name")?;
            let mut last = 64;
            for field in &fields {
                add_field_cells(&document, &row, &field.subfields, &mut last, |field| {
                    Some(field.to_string())
                })?;
            }
            table.append_child(&row)?;

            // Second level field descriptions
            let row = document.create_element("tr")?;
            row.set_attribute("class", "description")?;
            let mut last = 64;
            for field in &fields {
                add_field_cells(&document, &row, &field.subfields, &mut last, |field| {
                    field.description.clone()
                })?;
            }
            table.append_child(&row)?;
        }
        Err(e) => error_element.set_text_content(Some(&e.to_string())),
    }

    Ok(())
}

fn make_cell(
    document: &Document,
    contents: Option<&str>,
    colspan: usize,
) -> Result<Element, JsValue> {
    let cell = document.create_element("td")?;
    cell.set_attribute("colspan", &colspan.to_string())?;
    cell.set_text_content(contents);
    Ok(cell)
}

fn add_field_cells<F, S>(
    document: &Document,
    row: &Element,
    fields: &[FieldInfo],
    last: &mut usize,
    get_contents: F,
) -> Result<(), JsValue>
where
    F: Fn(&FieldInfo) -> Option<S>,
    S: Deref<Target = str>,
{
    for field in fields {
        if field.start + field.width != *last {
            // Add a filler
            let cell = make_cell(document, None, *last - field.start - field.width)?;
            row.append_child(&cell)?;
        }
        let cell = make_cell(document, get_contents(field).as_deref(), field.width)?;
        row.append_child(&cell)?;
        *last = field.start;
    }
    Ok(())
}
<commit_msg>Show long field names in web UI as abbr title.<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use aarch64_esr_decoder::{decode, parse_number, DecodeError, FieldInfo};
use std::ops::Deref;
use wasm_bindgen::prelude::*;
use web_sys::{Document, Element};

#[wasm_bindgen]
pub fn init() {
    #[cfg(feature = "console_error_panic_hook")]
    console_error_panic_hook::set_once();
}

#[wasm_bindgen]
pub fn decode_esr(esr: &str) -> Result<(), JsValue> {
    match parse_number(esr) {
        Ok(esr) => {
            let decoded = decode(esr);
            show_decoded(esr, decoded)?;
        }
        Err(_) => show_error("Invalid ESR"),
    }
    Ok(())
}

fn show_error(error: &str) {
    let document = web_sys::window()
        .expect("Couldn't find window")
        .document()
        .expect("Couldn't find document");
    let error_element = document
        .get_element_by_id("error")
        .expect("Couldn't find error element");
    let table = document
        .get_element_by_id("result_table")
        .expect("Couldn't find result table");
    // Clear output table.
    table.set_inner_html("");
    error_element.set_text_content(Some(error));
}

fn show_decoded(esr: u64, decoded: Result<Vec<FieldInfo>, DecodeError>) -> Result<(), JsValue> {
    let document = web_sys::window()
        .expect("Couldn't find window")
        .document()
        .expect("Couldn't find document");
    let error_element = document
        .get_element_by_id("error")
        .expect("Couldn't find error element");
    let table = document
        .get_element_by_id("result_table")
        .expect("Couldn't find result table");
    // Remove existing contents.
    error_element.set_inner_html("");
    table.set_inner_html("");

    // ESR in hexadecimal
    let row = document.create_element("tr")?;
    row.set_attribute("class", "value")?;
    let esr_hex = format!("{:016x}", esr);
    for digit in esr_hex.chars() {
        let cell = make_cell(&document, Some(&digit.to_string()), None, 4)?;
        row.append_child(&cell)?;
    }
    table.append_child(&row)?;

    // ESR in binary
    let row = document.create_element("tr")?;
    row.set_attribute("class", "value")?;
    for i in (0..u64::BITS).rev() {
        let bit = esr & (1 << i) != 0;
        let cell = make_cell(&document, Some(if bit { "1" } else { "0" }), None, 1)?;
        row.append_child(&cell)?;
    }
    table.append_child(&row)?;

    match decoded {
        Ok(fields) => {
            // Top-level field names and values
            let row = document.create_element("tr")?;
            row.set_attribute("class", "name")?;
            let mut last = 64;
            add_field_cells(
                &document,
                &row,
                &fields,
                &mut last,
                |field| Some(field.to_string()),
                |field| field.long_name,
            )?;
            table.append_child(&row)?;

            // Top-level field descriptions
            let row = document.create_element("tr")?;
            row.set_attribute("class", "description")?;
            let mut last = 64;
            add_field_cells(
                &document,
                &row,
                &fields,
                &mut last,
                |field| field.description.clone(),
                |_| None,
            )?;
            table.append_child(&row)?;

            // Second level field names and values
            let row = document.create_element("tr")?;
            row.set_attribute("class", "name")?;
            let mut last = 64;
            for field in &fields {
                add_field_cells(
                    &document,
                    &row,
                    &field.subfields,
                    &mut last,
                    |field| Some(field.to_string()),
                    |field| field.long_name,
                )?;
            }
            table.append_child(&row)?;

            // Second level field descriptions
            let row = document.create_element("tr")?;
            row.set_attribute("class", "description")?;
            let mut last = 64;
            for field in &fields {
                add_field_cells(
                    &document,
                    &row,
                    &field.subfields,
                    &mut last,
                    |field| field.description.clone(),
                    |_| None,
                )?;
            }
            table.append_child(&row)?;
        }
        Err(e) => error_element.set_text_content(Some(&e.to_string())),
    }

    Ok(())
}

fn make_cell(
    document: &Document,
    contents: Option<&str>,
    hover_title: Option<&str>,
    colspan: usize,
) -> Result<Element, JsValue> {
    let cell = document.create_element("td")?;
    cell.set_attribute("colspan", &colspan.to_string())?;
    if let Some(title) = hover_title {
        let abbr = document.create_element("abbr")?;
        abbr.set_attribute("title", title)?;
        abbr.set_text_content(contents);
        cell.append_child(&abbr)?;
    } else {
        cell.set_text_content(contents);
    }
    Ok(cell)
}

fn add_field_cells<F, G, S>(
    document: &Document,
    row: &Element,
    fields: &[FieldInfo],
    last: &mut usize,
    get_contents: F,
    get_hover_title: G,
) -> Result<(), JsValue>
where
    F: Fn(&FieldInfo) -> Option<S>,
    G: Fn(&FieldInfo) -> Option<&str>,
    S: Deref<Target = str>,
{
    for field in fields {
        if field.start + field.width != *last {
            // Add a filler
            let cell = make_cell(document, None, None, *last - field.start - field.width)?;
            row.append_child(&cell)?;
        }
        let cell = make_cell(
            document,
            get_contents(field).as_deref(),
            get_hover_title(field).as_deref(),
            field.width,
        )?;
        row.append_child(&cell)?;
        *last = field.start;
    }
    Ok(())
}
<|endoftext|>


<commit_before>//! Lazily initialized data.
//! Used in generated code.

use std::sync;
use std::sync::atomic::AtomicPtr;
use std::sync::atomic::Ordering;

/// Lazily initialized data.
pub struct LazyV2<T: Sync> {
    lock: sync::Once,
    ptr: AtomicPtr<T>,
}

unsafe impl<T: Sync> Sync for LazyV2<T> {}

impl<T: Sync> LazyV2<T> {
    /// Uninitialized `Lazy` object.
    pub const INIT: LazyV2<T> = LazyV2 {
        lock: sync::Once::new(),
        ptr: AtomicPtr::new(0 as *mut T),
    };

    /// Get lazy field value, initialize it with given function if not yet.
    pub fn get<F>(&'static self, init: F) -> &'static T
    where
        F: FnOnce() -> T,
    {
        self.lock.call_once(|| {
            self.ptr
                .store(Box::into_raw(Box::new(init())), Ordering::Relaxed);
        });
        unsafe { &*self.ptr.load(Ordering::Relaxed) }
    }
}

#[cfg(test)]
mod test {
    use std::sync::atomic::AtomicIsize;
    use std::sync::atomic::Ordering;
    use std::sync::Arc;
    use std::sync::Barrier;
    use std::thread;

    use super::LazyV2;

    #[test]
    fn many_threads_calling_get() {
        const N_THREADS: usize = if cfg!(miri) { 4 } else { 32 };
        const N_ITERS_IN_THREAD: usize = if cfg!(miri) { 4 } else { 32 };
        const N_ITERS: usize = if cfg!(miri) { 4 } else { 16 };

        static mut LAZY: LazyV2<String> = LazyV2::INIT;
        static CALL_COUNT: AtomicIsize = AtomicIsize::new(0);

        let value = "Hello, world!".to_owned();

        for _ in 0..N_ITERS {
            // Reset mutable state.
            unsafe {
                LAZY = LazyV2::INIT;
            }
            CALL_COUNT.store(0, Ordering::SeqCst);

            // Create a bunch of threads, all calling .get() at the same time.
            let mut threads = vec![];
            let barrier = Arc::new(Barrier::new(N_THREADS));

            for _ in 0..N_THREADS {
                let cloned_value_thread = value.clone();
                let cloned_barrier = barrier.clone();
                threads.push(thread::spawn(move || {
                    // Ensure all threads start at once to maximise contention.
                    cloned_barrier.wait();
                    for _ in 0..N_ITERS_IN_THREAD {
                        assert_eq!(&cloned_value_thread, unsafe {
                            LAZY.get(|| {
                                CALL_COUNT.fetch_add(1, Ordering::SeqCst);
                                cloned_value_thread.clone()
                            })
                        });
                    }
                }));
            }

            for thread in threads {
                thread.join().unwrap();
            }

            assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 1);
        }
    }
}
<commit_msg>Impl Drop for LazyV2<commit_after>//! Lazily initialized data.
//! Used in generated code.

use std::sync;
use std::sync::atomic::AtomicPtr;
use std::sync::atomic::Ordering;

/// Lazily initialized data.
pub struct LazyV2<T: Sync> {
    lock: sync::Once,
    ptr: AtomicPtr<T>,
}

unsafe impl<T: Sync> Sync for LazyV2<T> {}

impl<T: Sync> LazyV2<T> {
    /// Uninitialized `Lazy` object.
    pub const INIT: LazyV2<T> = LazyV2 {
        lock: sync::Once::new(),
        ptr: AtomicPtr::new(0 as *mut T),
    };

    /// Get lazy field value, initialize it with given function if not yet.
    pub fn get<F>(&'static self, init: F) -> &'static T
    where
        F: FnOnce() -> T,
    {
        self.lock.call_once(|| {
            self.ptr
                .store(Box::into_raw(Box::new(init())), Ordering::Relaxed);
        });
        unsafe { &*self.ptr.load(Ordering::Relaxed) }
    }
}

impl<T: Sync> Drop for LazyV2<T> {
    fn drop(&mut self) {
        let ptr = self.ptr.load(Ordering::Relaxed);
        if !ptr.is_null() {
            unsafe {
                Box::from_raw(ptr);
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::sync::atomic::AtomicIsize;
    use std::sync::atomic::Ordering;
    use std::sync::Arc;
    use std::sync::Barrier;
    use std::thread;

    use super::LazyV2;

    #[test]
    fn many_threads_calling_get() {
        const N_THREADS: usize = if cfg!(miri) { 4 } else { 32 };
        const N_ITERS_IN_THREAD: usize = if cfg!(miri) { 4 } else { 32 };
        const N_ITERS: usize = if cfg!(miri) { 4 } else { 16 };

        static mut LAZY: LazyV2<String> = LazyV2::INIT;
        static CALL_COUNT: AtomicIsize = AtomicIsize::new(0);

        let value = "Hello, world!".to_owned();

        for _ in 0..N_ITERS {
            // Reset mutable state.
            unsafe {
                LAZY = LazyV2::INIT;
            }
            CALL_COUNT.store(0, Ordering::SeqCst);

            // Create a bunch of threads, all calling .get() at the same time.
            let mut threads = vec![];
            let barrier = Arc::new(Barrier::new(N_THREADS));

            for _ in 0..N_THREADS {
                let cloned_value_thread = value.clone();
                let cloned_barrier = barrier.clone();
                threads.push(thread::spawn(move || {
                    // Ensure all threads start at once to maximise contention.
                    cloned_barrier.wait();
                    for _ in 0..N_ITERS_IN_THREAD {
                        assert_eq!(&cloned_value_thread, unsafe {
                            LAZY.get(|| {
                                CALL_COUNT.fetch_add(1, Ordering::SeqCst);
                                cloned_value_thread.clone()
                            })
                        });
                    }
                }));
            }

            for thread in threads {
                thread.join().unwrap();
            }

            assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 1);
        }
    }
}
<|endoftext|>