<commit_before>use std::{ptr, mem, fmt};
use std::sync::atomic::{AtomicUsize, AtomicBool};
use std::sync::atomic::Ordering::{SeqCst};

use super::arc::*;

pub const PAGE_SIZE: usize = 4096;
pub const BUFFER_END: usize = !0 as usize;

lazy_static! {
    pub static ref HEADER_SIZE: usize = mem::size_of::<SkipListEntry>();
    pub static ref FIRST_OR_SINGLE_CONTENT_SIZE: usize = PAGE_SIZE - *HEADER_SIZE;
    pub static ref OVERHEAD: usize = *HEADER_SIZE + *ARC_INNER_SIZE;
}

pub struct Pool {
    buffer: *mut u8,
    buffer_size: usize,
}

#[derive(Debug)]
struct Metadata {
    // TODO rip this out and replace with a free list
    // We probably want to keep 2 free lists -- A one-page
    // list and a larger objects list to avoid fragmentation
    lowest_known_free_index: usize,
}

impl fmt::Debug for Pool {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Pool")
            .field("buffer_size", &self.buffer_size)
            .field("metadata", &self.get_metadata_block())
            .field("blocks", &self.get_debug_blocks())
            .finish()
    }
}

impl Pool {
    pub fn new(buf: &mut [u8]) -> Pool {
        let ptr: *mut u8 = buf.as_mut_ptr();
        let p = Pool {
            buffer: ptr,
            buffer_size: buf.len(),
        };
        // Last page is metadata and not usable as a full page-aligned chunk anyway
        let last_skip_index = p.buffer_size - PAGE_SIZE;
        p.make_skip_entry(SkipListStart(last_skip_index), 0, BUFFER_END, false);
        p.make_skip_entry(SkipListStart(0), BUFFER_END, last_skip_index, true);
        p
    }
}

struct SkipListEntry {
    prev: AtomicUsize, // absolute buffer offset of previous SKE
    is_free: AtomicBool, // Whether the given memory is free
    next: AtomicUsize, // absolute buffer offset of next SKE
}

use self::IndexType::*;
enum IndexType {
    ArcStart(usize),
    DataStart(usize),
    SkipListStart(usize),
}

/// Public interface
impl Pool {
    pub fn malloc<T: Sized>(&self, data: T) -> Arc<T> {
        let size = mem::size_of::<T>();
        let chunked_size = round_up_to_nearest_page_size(size);
        let metadata = self.get_metadata_block();
        // Claim a block
        let (free_block_index, entry) = self.next_free_block_larger_than(chunked_size,
            SkipListStart(metadata.lowest_known_free_index));
        entry.is_free.store(false, SeqCst);

        let next_index = free_block_index + chunked_size;
        let following_index = entry.next.load(SeqCst);
        assert!(next_index <= following_index);
        // If we split a block, then we need to make a new entry
        if next_index < following_index {
            self.make_skip_entry(SkipListStart(next_index),
                following_index, free_block_index, true);
            let (_, following_entry) = self.header_for_byte_index(SkipListStart(following_index));
            following_entry.prev.store(next_index, SeqCst);
            entry.next.store(next_index, SeqCst);
        }

        // Update known free index if necessary (only necessary if we've used the lowest)
        if free_block_index == metadata.lowest_known_free_index {
            let (idx, _) = self.next_free_block_larger_than(0, SkipListStart(free_block_index));
            metadata.lowest_known_free_index = idx;
        }

        let inner = self.index_to_arc_inner(SkipListStart(free_block_index));
        inner.init(data);
        Arc::new(inner, self)
    }

    pub fn free<T>(&self, arc: &Arc<T>) {
        let metadata = self.get_metadata_block();
        let arc_index = self.arc_to_arc_inner_index(arc);
        let (this_idx, header) = self.header_for_byte_index(arc_index);
        let prev_idx = header.prev.load(SeqCst);
        let next_idx = header.next.load(SeqCst);
        let (_, prev) = self.header_for_byte_index(SkipListStart(prev_idx));
        let (_, next) = self.header_for_byte_index(SkipListStart(next_idx));

        header.is_free.store(true, SeqCst);
        if next.is_free.load(SeqCst) {
            // Merge with the next item, by encompassing it
            let next_next_idx = next.next.load(SeqCst);
            header.next.store(next_next_idx, SeqCst)
        }
        if prev.is_free.load(SeqCst) {
            // Merge by swallong this item with the previous item
            let next_idx = header.next.load(SeqCst);
            prev.next.store(next_idx, SeqCst);
        } else {
            // Update known free index if necessary
            if this_idx < metadata.lowest_known_free_index {
                metadata.lowest_known_free_index = this_idx;
            }
        }
    }

    pub fn deref<'a, T>(&'a self, arc: &'a Arc<T>) -> &'a T {
        let arc_index = self.arc_to_arc_inner_index(arc);
        self.index_to_arc_inner(arc_index).data
    }
}

/// Private interface
impl Pool {
    /// Get the metadata block, which always lives in the last page of the array
    fn get_metadata_block<'a>(&'a self) -> &'a mut Metadata {
        let metadata_index = self.buffer_size - PAGE_SIZE + *HEADER_SIZE;
        unsafe {
            mem::transmute(self.byte_index_to_live_ptr(metadata_index))
        }
    }

    /// Get the arc inner for a given index
    fn index_to_arc_inner<'a, T>(&'a self, index: IndexType) -> &'a mut ArcInner<T> {
        let offset = match index {
            ArcStart(i) => i ,
            DataStart(i) => i - *ARC_INNER_SIZE,
            SkipListStart(i) => i + *HEADER_SIZE,
        };
        unsafe {
            let ptr = self.byte_index_to_live_ptr(offset);
            mem::transmute(ptr)
        }
    }

    /// Get the arc inner for a given arc outer
    fn arc_to_arc_inner_index<'a, T>(&'a self, arc: &Arc<T>) -> IndexType {
        unsafe {
            let ptr: *mut u8 = mem::transmute(arc._ptr);
            ArcStart(self.live_ptr_to_byte_index(ptr))
        }
    }

    /// Does not take overhead into account
    fn next_free_block_larger_than<'a>(&'a self, size: usize, start_index: IndexType) -> (usize, &'a mut SkipListEntry) {
        let (idx, mut entry) = self.header_for_byte_index(start_index);
        if entry.is_free.load(SeqCst)
           && (entry.next.load(SeqCst) - idx) >= size {
            (idx, entry)
        } else {
            let next_index = entry.next.load(SeqCst);
            if next_index != BUFFER_END {
                self.next_free_block_larger_than(size, SkipListStart(next_index))
            } else {
                (BUFFER_END, entry)
            }
        }
    }

    fn live_ptr_to_byte_index(&self, ptr: *const u8) -> usize {
        let obj_addr = ptr as usize;
        let buf_addr = self.buffer as usize;
        if obj_addr < buf_addr {
            panic!("live_ptr_to_byte_index called with address below start of buffer!");
        }
        let offset = obj_addr - buf_addr;
        if offset > self.buffer_size {
            panic!("live_ptr_to_byte_index called with address past end of buffer!");
        }
        offset
    }

    unsafe fn byte_index_to_live_ptr(&self, byte_index: usize) -> *mut u8 {
        self.buffer.offset(byte_index as isize)
    }

    /// Find the skip list entry that precedes the given index's data
    fn header_for_byte_index<'a>(&'a self, index: IndexType) -> (usize, &'a mut SkipListEntry) {
        let offset = match index {
            ArcStart(i) => i - *HEADER_SIZE,
            DataStart(i) => i - *ARC_INNER_SIZE - *HEADER_SIZE,
            SkipListStart(i) => i,
        };
        unsafe {
            (offset, mem::transmute(self.buffer.offset(offset as isize)))
        }
    }

    /// Find the skip list entry that follows the given index's data
    fn footer_for_byte_index<'a>(&'a self, index: IndexType) -> (usize, &'a mut SkipListEntry) {
        let (_, entry) = self.header_for_byte_index(index);
        unsafe {
            let next_index = entry.next.load(SeqCst);
            let ptr = self.byte_index_to_live_ptr(next_index);
            (next_index, mem::transmute(ptr))
        }
    }

    fn make_skip_entry(&self, index: IndexType, prev: usize, next: usize, is_free: bool) {
        let (_, entry) = self.header_for_byte_index(index);
        entry.prev.store(prev, SeqCst);
        entry.next.store(next, SeqCst);
        entry.is_free.store(is_free, SeqCst);
    }

    fn get_debug_blocks<'a>(&'a self) -> Vec<_B> {
        let mut ret: Vec<_B> = Vec::new();
        let mut next_index: usize = 0;
        loop {
            let (idx, entry) = self.header_for_byte_index(SkipListStart(next_index));
            next_index = entry.next.load(SeqCst);
            if next_index == BUFFER_END {
                break
            }
            ret.push(_B {
                start: idx,
                size: next_index - idx - *OVERHEAD,
                is_free: entry.is_free.load(SeqCst)
            });
        }
        ret
    }
}

#[derive(Debug)]
struct _B {
    start: usize,
    size: usize,
    is_free: bool,
}

/// Take byte-length and compute the number of pages necessary to hold that many bytes.
/// Takes the space required for header/footer into account.
/// # Examples
/// ```
/// use lodestone::allocator::pool::*;
/// assert_eq!(1, calc_num_pages(5));
/// assert_eq!(1, calc_num_pages(PAGE_SIZE - *HEADER_SIZE));
/// assert_eq!(2, calc_num_pages(PAGE_SIZE - *HEADER_SIZE + 1));
/// assert_eq!(3, calc_num_pages(PAGE_SIZE*2));
/// ```
pub fn calc_num_pages(size: usize) -> usize {
    if size <= *FIRST_OR_SINGLE_CONTENT_SIZE {
        1
    } else {
        let tail_size = size - *FIRST_OR_SINGLE_CONTENT_SIZE;
        let spill = if tail_size % PAGE_SIZE > 0 {1} else {0};
        1 + tail_size / PAGE_SIZE + spill
    }
}

/// Take byte-length and round up to the nearest page's worth of bytes.
/// Takes overhead into account
/// # Examples
/// ```
/// use lodestone::allocator::pool::*;
/// assert_eq!(4096, round_up_to_nearest_page_size(5));
/// assert_eq!(4096, round_up_to_nearest_page_size(PAGE_SIZE - *HEADER_SIZE));
/// assert_eq!(8192, round_up_to_nearest_page_size(PAGE_SIZE - *HEADER_SIZE + 1));
/// assert_eq!(12288, round_up_to_nearest_page_size(PAGE_SIZE*2));
/// ```
pub fn round_up_to_nearest_page_size(size: usize) -> usize {
    calc_num_pages(size) * PAGE_SIZE
}

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

    struct TestStruct {
        a: usize,
        b: isize,
        c: bool,
    }

    #[test]
    fn test_printing_empty() {
        let mut buf: [u8; 0x2000] = [0; 0x2000];
        let p = Pool::new(&mut buf[..]);
        assert_eq!(
            "Pool { buffer_size: 8192, \
                metadata: Metadata { lowest_known_free_index: 0 }, \
                blocks: [_B { start: 0, size: 4056, is_free: true }] }",
            format!("{:?}", p)
        );
    }

    #[test]
    fn test_small_alloc_free() {
        let mut buf: [u8; 0x2000] = [0; 0x2000];
        let p = Pool::new(&mut buf[..]);

        let ts1 = TestStruct {
            a: 12345,
            b: -678,
            c: true,
        };
        let arc_ts1 = p.malloc(ts1);

        assert_eq!(
            "Pool { buffer_size: 8192, \
                metadata: Metadata { lowest_known_free_index: 18446744073709551615 }, \
                blocks: [_B { start: 0, size: 4056, is_free: false }] }",
            format!("{:?}", p)
        );

        //
        // assert_eq!(12345, arc_ts1.a);
        // assert_eq!(-678, arc_ts1.b);
        // assert_eq!(true, arc_ts1.c);

    }
}
<commit_msg>Malloc and Free are working and tested<commit_after>use std::{ptr, mem, fmt};
use std::sync::atomic::{AtomicUsize, AtomicBool};
use std::sync::atomic::Ordering::{SeqCst};

use super::arc::*;

pub const PAGE_SIZE: usize = 4096;
pub const BUFFER_END: usize = !0 as usize;

lazy_static! {
    pub static ref HEADER_SIZE: usize = mem::size_of::<SkipListEntry>();
    pub static ref FIRST_OR_SINGLE_CONTENT_SIZE: usize = PAGE_SIZE - *HEADER_SIZE;
    pub static ref OVERHEAD: usize = *HEADER_SIZE + *ARC_INNER_SIZE;
}

pub struct Pool {
    buffer: *mut u8,
    buffer_size: usize,
}

#[derive(Debug)]
struct Metadata {
    // TODO rip this out and replace with a free list
    // We probably want to keep 2 free lists -- A one-page
    // list and a larger objects list to avoid fragmentation
    lowest_known_free_index: usize,
}

impl fmt::Debug for Pool {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Pool")
            .field("buffer_size", &self.buffer_size)
            .field("metadata", &self.get_metadata_block())
            .field("blocks", &self.get_debug_blocks())
            .finish()
    }
}

impl Pool {
    pub fn new(buf: &mut [u8]) -> Pool {
        let ptr: *mut u8 = buf.as_mut_ptr();
        let p = Pool {
            buffer: ptr,
            buffer_size: buf.len(),
        };
        // Last page is metadata and not usable as a full page-aligned chunk anyway
        let last_skip_index = p.buffer_size - PAGE_SIZE;
        p.make_skip_entry(SkipListStart(last_skip_index), 0, BUFFER_END, false);
        p.make_skip_entry(SkipListStart(0), BUFFER_END, last_skip_index, true);
        p
    }
}

#[derive(Debug)]
struct SkipListEntry {
    prev: AtomicUsize, // absolute buffer offset of previous SKE
    is_free: AtomicBool, // Whether the given memory is free
    next: AtomicUsize, // absolute buffer offset of next SKE
}

use self::IndexType::*;
#[derive(Debug)]
enum IndexType {
    ArcStart(usize),
    DataStart(usize),
    SkipListStart(usize),
}

/// Public interface
impl Pool {
    pub fn malloc<T: Sized>(&self, data: T) -> Arc<T> {
        let size = mem::size_of::<T>();
        let chunked_size = round_up_to_nearest_page_size(size);
        let metadata = self.get_metadata_block();
        // Claim a block
        let (free_block_index, entry) = self.next_free_block_larger_than(chunked_size,
            SkipListStart(metadata.lowest_known_free_index));
        entry.is_free.store(false, SeqCst);

        let next_index = free_block_index + chunked_size;
        let following_index = entry.next.load(SeqCst);
        assert!(next_index <= following_index);
        // If we split a block, then we need to make a new entry
        if next_index < following_index {
            self.make_skip_entry(SkipListStart(next_index),
                free_block_index, following_index, true);
            let (_, following_entry) = self.header_for_byte_index(SkipListStart(following_index));
            following_entry.prev.store(next_index, SeqCst);
            entry.next.store(next_index, SeqCst);
        }

        // Update known free index if necessary (only necessary if we've used the lowest)
        if free_block_index == metadata.lowest_known_free_index {
            let (idx, _) = self.next_free_block_larger_than(0, SkipListStart(free_block_index));
            metadata.lowest_known_free_index = idx;
        }

        let inner = self.index_to_arc_inner(SkipListStart(free_block_index));
        inner.init(data);
        Arc::new(inner, self)
    }

    pub fn free<T>(&self, arc: &Arc<T>) {
        let metadata = self.get_metadata_block();
        let arc_index = self.arc_to_arc_inner_index(arc);
        let (this_idx, header) = self.header_for_byte_index(arc_index);
        let prev_idx = header.prev.load(SeqCst);
        let next_idx = header.next.load(SeqCst);

        header.is_free.store(true, SeqCst);
        // Update known free index if necessary
        if this_idx < metadata.lowest_known_free_index {
            metadata.lowest_known_free_index = this_idx;
        }

        if next_idx != BUFFER_END {
            let (_, next) = self.header_for_byte_index(SkipListStart(next_idx));
            if next.is_free.load(SeqCst) {
                // Merge with the next item, by encompassing it
                let next_next_idx = next.next.load(SeqCst);
                header.next.store(next_next_idx, SeqCst)
            }
        }
        if prev_idx != BUFFER_END {
            let (_, prev) = self.header_for_byte_index(SkipListStart(prev_idx));
            if prev.is_free.load(SeqCst) {
                // Merge by swallong this item with the previous item
                let next_idx = header.next.load(SeqCst);
                prev.next.store(next_idx, SeqCst);
            }
        }
    }

    pub fn deref<'a, T>(&'a self, arc: &'a Arc<T>) -> &'a T {
        let arc_index = self.arc_to_arc_inner_index(arc);
        println!("Derefing Arc inner at {:?}", arc_index);
        &self.index_to_arc_inner(arc_index).data
    }
}

/// Private interface
impl Pool {
    /// Get the metadata block, which always lives in the last page of the array
    fn get_metadata_block<'a>(&'a self) -> &'a mut Metadata {
        let metadata_index = self.buffer_size - PAGE_SIZE + *HEADER_SIZE;
        unsafe {
            mem::transmute(self.byte_index_to_live_ptr(metadata_index))
        }
    }

    /// Get the arc inner for a given index
    fn index_to_arc_inner<'a, T>(&'a self, index: IndexType) -> &'a mut ArcInner<T> {
        let offset = match index {
            ArcStart(i) => i,
            DataStart(i) => i - *ARC_INNER_SIZE,
            SkipListStart(i) => i + *HEADER_SIZE,
        };
        unsafe {
            let ptr = self.byte_index_to_live_ptr(offset);
            mem::transmute(ptr)
        }
    }

    /// Get the arc inner for a given arc outer
    fn arc_to_arc_inner_index<'a, T>(&'a self, arc: &Arc<T>) -> IndexType {
        unsafe {
            let ptr: *mut u8 = mem::transmute(arc._ptr);
            ArcStart(self.live_ptr_to_byte_index(ptr))
        }
    }

    /// Does not take overhead into account
    fn next_free_block_larger_than<'a>(&'a self, size: usize, start_index: IndexType) -> (usize, &'a mut SkipListEntry) {
        let (idx, mut entry) = self.header_for_byte_index(start_index);
        if entry.is_free.load(SeqCst)
           && (entry.next.load(SeqCst) - idx) >= size {
            (idx, entry)
        } else {
            let next_index = entry.next.load(SeqCst);
            if next_index != BUFFER_END {
                self.next_free_block_larger_than(size, SkipListStart(next_index))
            } else {
                (BUFFER_END, entry)
            }
        }
    }

    fn live_ptr_to_byte_index(&self, ptr: *const u8) -> usize {
        let obj_addr = ptr as usize;
        let buf_addr = self.buffer as usize;
        if obj_addr < buf_addr {
            panic!("live_ptr_to_byte_index called with address below start of buffer!");
        }
        let offset = obj_addr - buf_addr;
        if offset > self.buffer_size {
            panic!("live_ptr_to_byte_index called with address past end of buffer!");
        }
        // println!("Converted live address {} to offset {}", obj_addr, offset);
        offset
    }

    unsafe fn byte_index_to_live_ptr(&self, byte_index: usize) -> *mut u8 {
        let ptr = self.buffer.offset(byte_index as isize);
        // println!("Converted offset {} to live address {:?}", byte_index, ptr);
        ptr
    }

    /// Find the skip list entry that precedes the given index's data
    fn header_for_byte_index<'a>(&'a self, index: IndexType) -> (usize, &'a mut SkipListEntry) {
        let offset = match index {
            ArcStart(i) => i - *HEADER_SIZE,
            DataStart(i) => i - *ARC_INNER_SIZE - *HEADER_SIZE,
            SkipListStart(i) => i,
        };
        unsafe {
            (offset, mem::transmute(self.buffer.offset(offset as isize)))
        }
    }

    /// Find the skip list entry that follows the given index's data
    fn footer_for_byte_index<'a>(&'a self, index: IndexType) -> (usize, &'a mut SkipListEntry) {
        let (_, entry) = self.header_for_byte_index(index);
        unsafe {
            let next_index = entry.next.load(SeqCst);
            let ptr = self.byte_index_to_live_ptr(next_index);
            (next_index, mem::transmute(ptr))
        }
    }

    fn make_skip_entry(&self, index: IndexType, prev: usize, next: usize, is_free: bool) {
        let (_, entry) = self.header_for_byte_index(index);
        entry.prev.store(prev, SeqCst);
        entry.next.store(next, SeqCst);
        entry.is_free.store(is_free, SeqCst);
    }

    fn get_debug_blocks<'a>(&'a self) -> Vec<_B> {
        let mut ret: Vec<_B> = Vec::new();
        let mut next_index: usize = 0;
        loop {
            let (idx, entry) = self.header_for_byte_index(SkipListStart(next_index));
            next_index = entry.next.load(SeqCst);
            let prev_index = entry.prev.load(SeqCst);
            if next_index == BUFFER_END {
                break
            }
            ret.push(_B {
                start: idx,
                capacity: next_index - idx - *OVERHEAD,
                next: next_index,
                prev: prev_index,
                is_free: entry.is_free.load(SeqCst)
            });
        }
        ret
    }
}

#[derive(Debug)]
struct _B {
    start: usize,
    capacity: usize,
    next: usize,
    prev: usize,
    is_free: bool,
}

/// Take byte-length and compute the number of pages necessary to hold that many bytes.
/// Takes the space required for header/footer into account.
/// # Examples
/// ```
/// use lodestone::allocator::pool::*;
/// assert_eq!(1, calc_num_pages(5));
/// assert_eq!(1, calc_num_pages(PAGE_SIZE - *HEADER_SIZE));
/// assert_eq!(2, calc_num_pages(PAGE_SIZE - *HEADER_SIZE + 1));
/// assert_eq!(3, calc_num_pages(PAGE_SIZE*2));
/// ```
pub fn calc_num_pages(size: usize) -> usize {
    if size <= *FIRST_OR_SINGLE_CONTENT_SIZE {
        1
    } else {
        let tail_size = size - *FIRST_OR_SINGLE_CONTENT_SIZE;
        let spill = if tail_size % PAGE_SIZE > 0 {1} else {0};
        1 + tail_size / PAGE_SIZE + spill
    }
}

/// Take byte-length and round up to the nearest page's worth of bytes.
/// Takes overhead into account
/// # Examples
/// ```
/// use lodestone::allocator::pool::*;
/// assert_eq!(4096, round_up_to_nearest_page_size(5));
/// assert_eq!(4096, round_up_to_nearest_page_size(PAGE_SIZE - *HEADER_SIZE));
/// assert_eq!(8192, round_up_to_nearest_page_size(PAGE_SIZE - *HEADER_SIZE + 1));
/// assert_eq!(12288, round_up_to_nearest_page_size(PAGE_SIZE*2));
/// ```
pub fn round_up_to_nearest_page_size(size: usize) -> usize {
    calc_num_pages(size) * PAGE_SIZE
}

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

    struct TestStruct {
        a: usize,
        b: isize,
        c: bool,
    }

    #[test]
    fn test_printing_empty() {
        let mut buf: [u8; 0x2000] = [0; 0x2000];
        let p = Pool::new(&mut buf[..]);
        assert_eq!(
            "Pool { buffer_size: 8192, \
                metadata: Metadata { lowest_known_free_index: 0 }, \
                blocks: [\
                _B { start: 0, capacity: 4056, next: 4096, prev: 18446744073709551615, is_free: true }\
                ] }",
            format!("{:?}", p)
        );
    }

    #[test]
    fn test_small_alloc_free() {
        let mut buf: [u8; 0x4000] = [0; 0x4000];
        let p = Pool::new(&mut buf[..]);

        let arc_ts1 = p.malloc(TestStruct {
            a: 12345,
            b: -678,
            c: true,
        });

        assert_eq!(
            "Pool { buffer_size: 16384, \
                metadata: Metadata { lowest_known_free_index: 4096 }, \
                blocks: [\
                _B { start: 0, capacity: 4056, next: 4096, prev: 18446744073709551615, is_free: false }, \
                _B { start: 4096, capacity: 8152, next: 12288, prev: 0, is_free: true }\
                ] }",
            format!("{:?}", p)
        );

        assert_eq!(12345, arc_ts1.a);
        assert_eq!(-678, arc_ts1.b);
        assert_eq!(true, arc_ts1.c);

        let arc_ts2 = p.malloc(TestStruct {
            a: 12345,
            b: -678,
            c: true,
        });
        assert_eq!(
            "Pool { buffer_size: 16384, \
                metadata: Metadata { lowest_known_free_index: 8192 }, \
                blocks: [\
                _B { start: 0, capacity: 4056, next: 4096, prev: 18446744073709551615, is_free: false }, \
                _B { start: 4096, capacity: 4056, next: 8192, prev: 0, is_free: false }, \
                _B { start: 8192, capacity: 4056, next: 12288, prev: 4096, is_free: true }\
                ] }",
            format!("{:?}", p)
        );

        p.free(&arc_ts1);

        assert_eq!(
            "Pool { buffer_size: 16384, \
                metadata: Metadata { lowest_known_free_index: 0 }, \
                blocks: [\
                _B { start: 0, capacity: 4056, next: 4096, prev: 18446744073709551615, is_free: true }, \
                _B { start: 4096, capacity: 4056, next: 8192, prev: 0, is_free: false }, \
                _B { start: 8192, capacity: 4056, next: 12288, prev: 4096, is_free: true }\
                ] }",
            format!("{:?}", p)
        );

        p.free(&arc_ts2);

        assert_eq!(
            "Pool { buffer_size: 16384, \
                metadata: Metadata { lowest_known_free_index: 0 }, \
                blocks: [\
                _B { start: 0, capacity: 12248, next: 12288, prev: 18446744073709551615, is_free: true }\
                ] }",
            format!("{:?}", p)
        );
    }
}
<|endoftext|>


<commit_before>//! Functions for scoring a set of predictions, i.e. evaluating
//! how close predictions and truth are. All functions in this
//! module obey the convention that higher is better.

use linalg::{BaseMatrix, Matrix};
use learning::toolkit::cost_fn::{CostFunc, MeanSqError};

/// Returns the fraction of outputs which match their target.
pub fn accuracy<I>(outputs: I, targets: I) -> f64
    where I: ExactSizeIterator,
          I::Item: PartialEq
{
    assert!(outputs.len() == targets.len());
    let len = outputs.len() as f64;
    let correct = outputs
        .zip(targets)
        .filter(|&(ref x, ref y)| x == y)
        .count();
    correct as f64 / len
}

/// Returns the fraction of outputs rows which match their target.
pub fn row_accuracy(outputs: &Matrix<f64>, targets: &Matrix<f64>) -> f64 {
    accuracy(outputs.iter_rows(), targets.iter_rows())
}

// TODO: generalise to accept arbitrary iterators of diff-able things
/// Returns the additive inverse of the mean-squared-error of the
/// outputs. So higher is better, and the returned value is always
/// negative.
pub fn neg_mean_squared_error(outputs: &Matrix<f64>, targets: &Matrix<f64>) -> f64
{
    // MeanSqError divides the actual mean squared error by two.
    -2f64 * MeanSqError::cost(outputs, targets)
}

#[cfg(test)]
mod tests {
    use linalg::Matrix;
    use super::{accuracy, neg_mean_squared_error};

    #[test]
    fn test_accuracy() {
        let outputs = [1, 2, 3, 4, 5, 6];
        let targets = [1, 2, 3, 3, 5, 1];
        assert_eq!(accuracy(outputs.iter(), targets.iter()), 2f64/3f64);
    }

    #[test]
    fn test_neg_mean_squared_error_1d() {
        let outputs = Matrix::new(3, 1, vec![1f64, 2f64, 3f64]);
        let targets = Matrix::new(3, 1, vec![2f64, 4f64, 3f64]);
        assert_eq!(neg_mean_squared_error(&outputs, &targets), -5f64/3f64);
    }

    #[test]
    fn test_neg_mean_squared_error_2d() {
        let outputs = Matrix::new(3, 2, vec![
            1f64, 2f64,
            3f64, 4f64,
            5f64, 6f64
            ]);
        let targets = Matrix::new(3, 2, vec![
            1.5f64, 2.5f64,
            5f64,   6f64,
            5.5f64, 6.5f64
            ]);
        assert_eq!(neg_mean_squared_error(&outputs, &targets), -3f64);
    }
}
<commit_msg>ENH: Add classification scores (#168)<commit_after>//! Functions for scoring a set of predictions, i.e. evaluating
//! how close predictions and truth are. All functions in this
//! module obey the convention that higher is better.

use libnum::{Zero, One};

use linalg::{BaseMatrix, Matrix};
use learning::toolkit::cost_fn::{CostFunc, MeanSqError};

// ************************************
// Classification Scores
// ************************************

/// Returns the fraction of outputs which match their target.
///
/// # Arguments
///
/// * `outputs` - Iterator of output (predicted) labels.
/// * `targets` - Iterator of expected (actual) labels.
///
/// # Examples
///
/// ```
/// use rusty_machine::analysis::score::accuracy;
/// let outputs = [1, 1, 1, 0, 0, 0];
/// let targets = [1, 1, 0, 0, 1, 1];
///
/// assert_eq!(accuracy(outputs.iter(), targets.iter()), 0.5);
/// ```
///
/// # Panics
///
/// - outputs and targets have different length
pub fn accuracy<I>(outputs: I, targets: I) -> f64
    where I: ExactSizeIterator,
          I::Item: PartialEq
{
    assert!(outputs.len() == targets.len(), "outputs and targets must have the same length");
    let len = outputs.len() as f64;
    let correct = outputs
        .zip(targets)
        .filter(|&(ref x, ref y)| x == y)
        .count();
    correct as f64 / len
}

/// Returns the fraction of outputs rows which match their target.
pub fn row_accuracy(outputs: &Matrix<f64>, targets: &Matrix<f64>) -> f64 {
    accuracy(outputs.iter_rows(), targets.iter_rows())
}

/// Returns the precision score for 2 class classification.
///
/// Precision is calculated with true-positive / (true-positive + false-positive),
/// see [Precision and Recall](https://en.wikipedia.org/wiki/Precision_and_recall) for details.
///
/// # Arguments
///
/// * `outputs` - Iterator of output (predicted) labels which only contains 0 or 1.
/// * `targets` - Iterator of expected (actual) labels which only contains 0 or 1.
///
/// # Examples
///
/// ```
/// use rusty_machine::analysis::score::precision;
/// let outputs = [1, 1, 1, 0, 0, 0];
/// let targets = [1, 1, 0, 0, 1, 1];
///
/// assert_eq!(precision(outputs.iter(), targets.iter()), 2.0f64 / 3.0f64);
/// ```
///
/// # Panics
///
/// - outputs and targets have different length
/// - outputs or targets contains a value which is not 0 or 1
pub fn precision<'a, I, T>(outputs: I, targets: I) -> f64
    where I: ExactSizeIterator<Item=&'a T>,
          T: 'a + PartialEq + Zero + One
{
    assert!(outputs.len() == targets.len(), "outputs and targets must have the same length");

    let mut tpfp = 0.0f64;
    let mut tp = 0.0f64;

    for (ref o, ref t) in outputs.zip(targets) {
        if *o == &T::one() {
            tpfp += 1.0f64;
            if *t == &T::one() {
                tp += 1.0f64;
            }
        }
        if ((*t != &T::zero()) & (*t != &T::one())) |
           ((*o != &T::zero()) & (*o != &T::one())) {
            panic!("precision must be used for 2 class classification")
        }
    }
    tp / tpfp
}

/// Returns the recall score for 2 class classification.
///
/// Recall is calculated with true-positive / (true-positive + false-negative),
/// see [Precision and Recall](https://en.wikipedia.org/wiki/Precision_and_recall) for details.
///
/// # Arguments
///
/// * `outputs` - Iterator of output (predicted) labels which only contains 0 or 1.
/// * `targets` - Iterator of expected (actual) labels which only contains 0 or 1.
///
/// # Examples
///
/// ```
/// use rusty_machine::analysis::score::recall;
/// let outputs = [1, 1, 1, 0, 0, 0];
/// let targets = [1, 1, 0, 0, 1, 1];
///
/// assert_eq!(recall(outputs.iter(), targets.iter()), 0.5);
/// ```
///
/// # Panics
///
/// - outputs and targets have different length
/// - outputs or targets contains a value which is not 0 or 1
pub fn recall<'a, I, T>(outputs: I, targets: I) -> f64
    where I: ExactSizeIterator<Item=&'a T>,
          T: 'a + PartialEq + Zero + One
{
    assert!(outputs.len() == targets.len(), "outputs and targets must have the same length");

    let mut tpfn = 0.0f64;
    let mut tp = 0.0f64;

    for (ref o, ref t) in outputs.zip(targets) {
        if *t == &T::one() {
            tpfn += 1.0f64;
            if *o == &T::one() {
                tp += 1.0f64;
            }
        }
        if ((*t != &T::zero()) & (*t != &T::one())) |
           ((*o != &T::zero()) & (*o != &T::one())) {
            panic!("recall must be used for 2 class classification")
        }
    }
    tp / tpfn
}

/// Returns the f1 score for 2 class classification.
///
/// F1-score is calculated with 2 * precision * recall / (precision + recall),
/// see [F1 score](https://en.wikipedia.org/wiki/F1_score) for details.
///
/// # Arguments
///
/// * `outputs` - Iterator of output (predicted) labels which only contains 0 or 1.
/// * `targets` - Iterator of expected (actual) labels which only contains 0 or 1.
///
/// # Examples
///
/// ```
/// use rusty_machine::analysis::score::f1;
/// let outputs = [1, 1, 1, 0, 0, 0];
/// let targets = [1, 1, 0, 0, 1, 1];
///
/// assert_eq!(f1(outputs.iter(), targets.iter()), 0.5714285714285714);
/// ```
///
/// # Panics
///
/// - outputs and targets have different length
/// - outputs or targets contains a value which is not 0 or 1
pub fn f1<'a, I, T>(outputs: I, targets: I) -> f64
    where I: ExactSizeIterator<Item=&'a T>,
          T: 'a + PartialEq + Zero + One
{
    assert!(outputs.len() == targets.len(), "outputs and targets must have the same length");

    let mut tpos = 0.0f64;
    let mut fpos = 0.0f64;
    let mut fneg = 0.0f64;

    for (ref o, ref t) in outputs.zip(targets) {
        if (*o == &T::one()) & (*t == &T::one()) {
            tpos += 1.0f64;
        } else if *t == &T::one() {
            fpos += 1.0f64;
        } else if *o == &T::one() {
            fneg += 1.0f64;
        }
        if ((*t != &T::zero()) & (*t != &T::one())) |
           ((*o != &T::zero()) & (*o != &T::one())) {
            panic!("f1-score must be used for 2 class classification")
        }
    }
    2.0f64 * tpos / (2.0f64 * tpos + fneg + fpos)
}

// ************************************
// Regression Scores
// ************************************

// TODO: generalise to accept arbitrary iterators of diff-able things
/// Returns the additive inverse of the mean-squared-error of the
/// outputs. So higher is better, and the returned value is always
/// negative.
pub fn neg_mean_squared_error(outputs: &Matrix<f64>, targets: &Matrix<f64>) -> f64
{
    // MeanSqError divides the actual mean squared error by two.
    -2f64 * MeanSqError::cost(outputs, targets)
}

#[cfg(test)]
mod tests {
    use linalg::Matrix;
    use super::{accuracy, precision, recall, f1, neg_mean_squared_error};

    #[test]
    fn test_accuracy() {
        let outputs = [1, 2, 3, 4, 5, 6];
        let targets = [1, 2, 3, 3, 5, 1];
        assert_eq!(accuracy(outputs.iter(), targets.iter()), 2f64/3f64);

        let outputs = [1, 1, 1, 0, 0, 0];
        let targets = [1, 1, 1, 0, 0, 1];
        assert_eq!(accuracy(outputs.iter(), targets.iter()), 5.0f64 / 6.0f64);
    }

    #[test]
    fn test_precision() {
        let outputs = [1, 1, 1, 0, 0, 0];
        let targets = [1, 1, 0, 0, 1, 1];
        assert_eq!(precision(outputs.iter(), targets.iter()), 2.0f64 / 3.0f64);

        let outputs = [1, 1, 1, 0, 1, 1];
        let targets = [1, 1, 0, 0, 1, 1];
        assert_eq!(precision(outputs.iter(), targets.iter()), 0.8);

        let outputs = [0, 0, 0, 1, 1, 1];
        let targets = [1, 1, 1, 1, 1, 0];
        assert_eq!(precision(outputs.iter(), targets.iter()), 2.0f64 / 3.0f64);

        let outputs = [1, 1, 1, 1, 1, 0];
        let targets = [0, 0, 0, 1, 1, 1];
        assert_eq!(precision(outputs.iter(), targets.iter()), 0.4);
    }

    #[test]
    #[should_panic]
    fn test_precision_outputs_not_2class() {
        let outputs = [1, 2, 1, 0, 0, 0];
        let targets = [1, 1, 0, 0, 1, 1];
        precision(outputs.iter(), targets.iter());
    }

    #[test]
    #[should_panic]
    fn test_precision_targets_not_2class() {
        let outputs = [1, 0, 1, 0, 0, 0];
        let targets = [1, 2, 0, 0, 1, 1];
        precision(outputs.iter(), targets.iter());
    }

    #[test]
    fn test_recall() {
        let outputs = [1, 1, 1, 0, 0, 0];
        let targets = [1, 1, 0, 0, 1, 1];
        assert_eq!(recall(outputs.iter(), targets.iter()), 0.5);

        let outputs = [1, 1, 1, 0, 1, 1];
        let targets = [1, 1, 0, 0, 1, 1];
        assert_eq!(recall(outputs.iter(), targets.iter()), 1.0);

        let outputs = [0, 0, 0, 1, 1, 1];
        let targets = [1, 1, 1, 1, 1, 0];
        assert_eq!(recall(outputs.iter(), targets.iter()), 0.4);

        let outputs = [1, 1, 1, 1, 1, 0];
        let targets = [0, 0, 0, 1, 1, 1];
        assert_eq!(recall(outputs.iter(), targets.iter()), 2.0f64 / 3.0f64);
    }

    #[test]
    #[should_panic]
    fn test_recall_outputs_not_2class() {
        let outputs = [1, 2, 1, 0, 0, 0];
        let targets = [1, 1, 0, 0, 1, 1];
        recall(outputs.iter(), targets.iter());
    }

    #[test]
    #[should_panic]
    fn test_recall_targets_not_2class() {
        let outputs = [1, 0, 1, 0, 0, 0];
        let targets = [1, 2, 0, 0, 1, 1];
        recall(outputs.iter(), targets.iter());
    }

    #[test]
    fn test_f1() {
        let outputs = [1, 1, 1, 0, 0, 0];
        let targets = [1, 1, 0, 0, 1, 1];
        assert_eq!(f1(outputs.iter(), targets.iter()), 0.5714285714285714);

        let outputs = [1, 1, 1, 0, 1, 1];
        let targets = [1, 1, 0, 0, 1, 1];
        assert_eq!(f1(outputs.iter(), targets.iter()), 0.8888888888888888);

        let outputs = [0, 0, 0, 1, 1, 1];
        let targets = [1, 1, 1, 1, 1, 0];
        assert_eq!(f1(outputs.iter(), targets.iter()), 0.5);

        let outputs = [1, 1, 1, 1, 1, 0];
        let targets = [0, 0, 0, 1, 1, 1];
        assert_eq!(f1(outputs.iter(), targets.iter()), 0.5);
    }

    #[test]
    #[should_panic]
    fn test_f1_outputs_not_2class() {
        let outputs = [1, 2, 1, 0, 0, 0];
        let targets = [1, 1, 0, 0, 1, 1];
        f1(outputs.iter(), targets.iter());
    }

    #[test]
    #[should_panic]
    fn test_f1_targets_not_2class() {
        let outputs = [1, 0, 1, 0, 0, 0];
        let targets = [1, 2, 0, 0, 1, 1];
        f1(outputs.iter(), targets.iter());
    }

    #[test]
    fn test_neg_mean_squared_error_1d() {
        let outputs = Matrix::new(3, 1, vec![1f64, 2f64, 3f64]);
        let targets = Matrix::new(3, 1, vec![2f64, 4f64, 3f64]);
        assert_eq!(neg_mean_squared_error(&outputs, &targets), -5f64/3f64);
    }

    #[test]
    fn test_neg_mean_squared_error_2d() {
        let outputs = Matrix::new(3, 2, vec![
            1f64, 2f64,
            3f64, 4f64,
            5f64, 6f64
            ]);
        let targets = Matrix::new(3, 2, vec![
            1.5f64, 2.5f64,
            5f64,   6f64,
            5.5f64, 6.5f64
            ]);
        assert_eq!(neg_mean_squared_error(&outputs, &targets), -3f64);
    }
}
<|endoftext|>


<commit_before>extern crate amq_protocol_types;

use amq_protocol_types::*;
use amq_protocol_types::generation::gen_value;
use amq_protocol_types::parsing::parse_value;

#[test]
fn test_full_integration() {
    let mut table  = FieldTable::new();
    let mut table2 = FieldTable::new();

    table2.insert("foo".to_string(), AMQPValue::DecimalValue(DecimalValue { scale: 55, value: 999, }));
    table2.insert("baz".to_string(), AMQPValue::LongString("blah42".to_string()));

    table.insert("foo".to_string(),  AMQPValue::FieldArray(vec![AMQPValue::Boolean(true), AMQPValue::Void]));
    table.insert("oof".to_string(),  AMQPValue::FieldArray(FieldArray::new()));
    table.insert("bar".to_string(),  AMQPValue::FieldTable(FieldTable::new()));
    table.insert("blah".to_string(), AMQPValue::Boolean(false));
    table.insert("aaaa".to_string(), AMQPValue::ShortShortInt(42));
    table.insert("bbbb".to_string(), AMQPValue::ShortShortUInt(64));
    table.insert("cccc".to_string(), AMQPValue::ShortInt(32));
    table.insert("dddd".to_string(), AMQPValue::ShortUInt(132));
    table.insert("eeee".to_string(), AMQPValue::LongInt(-53));
    table.insert("ffff".to_string(), AMQPValue::LongUInt(66666));
    table.insert("gggg".to_string(), AMQPValue::LongLongInt(-9999));
    table.insert("hhhh".to_string(), AMQPValue::ByteArray(vec![42, 1, 2, 3]));
    table.insert("iiii".to_string(), AMQPValue::Float(42.3));
    table.insert("tabl".to_string(), AMQPValue::FieldTable(table2));
    table.insert("jjjj".to_string(), AMQPValue::Double(0.00987654321));
    table.insert("kkkk".to_string(), AMQPValue::Timestamp(1234567890));
    table.insert("llll".to_string(), AMQPValue::Void);

    let value              = AMQPValue::FieldTable(table);
    let mut buf: [u8; 512] = [0; 512];

    assert_eq!(parse_value(gen_value((&mut buf[..], 0), &value).unwrap().0).to_result().unwrap(), value);
}
<commit_msg>types: avoid unwrap in integration test<commit_after>extern crate amq_protocol_types;
extern crate nom;

use amq_protocol_types::*;
use amq_protocol_types::generation::gen_value;
use amq_protocol_types::parsing::parse_value;

use nom::IResult;

#[test]
fn test_full_integration() {
    let mut table  = FieldTable::new();
    let mut table2 = FieldTable::new();

    table2.insert("foo".to_string(), AMQPValue::DecimalValue(DecimalValue { scale: 55, value: 999, }));
    table2.insert("baz".to_string(), AMQPValue::LongString("blah42".to_string()));

    table.insert("foo".to_string(),  AMQPValue::FieldArray(vec![AMQPValue::Boolean(true), AMQPValue::Void]));
    table.insert("oof".to_string(),  AMQPValue::FieldArray(FieldArray::new()));
    table.insert("bar".to_string(),  AMQPValue::FieldTable(FieldTable::new()));
    table.insert("blah".to_string(), AMQPValue::Boolean(false));
    table.insert("aaaa".to_string(), AMQPValue::ShortShortInt(42));
    table.insert("bbbb".to_string(), AMQPValue::ShortShortUInt(64));
    table.insert("cccc".to_string(), AMQPValue::ShortInt(32));
    table.insert("dddd".to_string(), AMQPValue::ShortUInt(132));
    table.insert("eeee".to_string(), AMQPValue::LongInt(-53));
    table.insert("ffff".to_string(), AMQPValue::LongUInt(66666));
    table.insert("gggg".to_string(), AMQPValue::LongLongInt(-9999));
    table.insert("hhhh".to_string(), AMQPValue::ByteArray(vec![42, 1, 2, 3]));
    table.insert("iiii".to_string(), AMQPValue::Float(42.3));
    table.insert("tabl".to_string(), AMQPValue::FieldTable(table2));
    table.insert("jjjj".to_string(), AMQPValue::Double(0.00987654321));
    table.insert("kkkk".to_string(), AMQPValue::Timestamp(1234567890));
    table.insert("llll".to_string(), AMQPValue::Void);

    let value              = AMQPValue::FieldTable(table);
    let mut buf: [u8; 199] = [0; 199];

    assert_eq!(parse_value(gen_value((&mut buf[..], 0), &value).unwrap().0), IResult::Done(&[][..], value));
}
<|endoftext|>


<commit_before>use chrono::*;
use fast_chemail::is_valid_email;
use quoted_printable;
use std::io::{Error, ErrorKind, Result};

const FROM_ADDRESS: &str = "\"Karte von morgen\" <no-reply@kartevonmorgen.org>";

pub fn create(to: &[String], subject: &str, body: &str) -> Result<String> {
    let to: Vec<_> = to
        .into_iter()
        .filter(|m| is_valid_email(m))
        .cloned()
        .collect();

    if to.is_empty() {
        return Err(Error::new(
            ErrorKind::Other,
            "No valid email adresses specified",
        ));
    }

    debug_assert!(!subject.is_empty());
    let subject = format!(
        "=?UTF-8?Q?{}?=",
        quoted_printable::encode_to_str(subject.as_bytes())
    );

    let now = Local::now();

    let email = format!(
        "Date:{date}\r\n\
         From:{from}\r\n\
         To:{to}\r\n\
         Subject:{subject}\r\n\
         MIME-Version: 1.0\r\n\
         Content-Type: text/plain; charset=utf-8\r\n\r\n\
         {body}",
        date = now.to_rfc2822(),
        from = FROM_ADDRESS,
        to = to.join(","),
        subject = subject,
        body = body
    );

    debug!("composed email: {}", &email);

    Ok(email)
}

#[cfg(all(not(test), feature = "email"))]
pub mod sendmail {
    use super::*;
    use std::io::prelude::*;
    use std::process::{Command, Stdio};

    pub fn send(mail: &str) -> Result<()> {
        let mut child = Command::new("sendmail")
            .arg("-t")
            .stdin(Stdio::piped())
            .spawn()?;
        child
            .stdin
            .as_mut()
            .ok_or_else(|| Error::new(ErrorKind::Other, "Could not get stdin"))?
            .write_all(mail.as_bytes())?;
        child.wait_with_output()?;
        Ok(())
    }
}

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

    #[test]
    fn create_simple_mail() {
        let mail = create(&vec!["mail@test.org".into()], "My Subject", "Hello Mail").unwrap();
        let expected = "From:\"Karte von morgen\" <no-reply@kartevonmorgen.org>\r\n\
                        To:mail@test.org\r\n\
                        Subject:=?UTF-8?Q?My Subject?=\r\n\
                        MIME-Version: 1.0\r\n\
                        Content-Type: text/plain; charset=utf-8\r\n\r\n\
                        Hello Mail";
        assert!(mail.contains(expected));
    }

    #[test]
    fn check_addresses() {
        assert!(create(&vec![], "foo", "bar").is_err());
        assert!(create(&vec!["not-valid".into()], "foo", "bar").is_err());
    }
}
<commit_msg>Encode e-mail subject according to RFC 2047<commit_after>use chrono::*;
use fast_chemail::is_valid_email;
use quoted_printable;
use std::io::{Error, ErrorKind, Result};

const FROM_ADDRESS: &str = "\"Karte von morgen\" <no-reply@kartevonmorgen.org>";

// quoted_printable limits the length of lines to 76 chars
// and otherwise inserts unintended line breaks! The max.
// length of a header line is 78 chars including the \r\n
// line break.
const MAX_HEADER_FIELD_LEN: usize = 76;

const LINE_BREAK: &str = "\r\n";

fn encode_header_field_partially(input: &str, encoded_max_len: usize) -> (String, usize) {
    // overhead of the encoding (see string formatting literal below)
    debug_assert!(encoded_max_len >= "=?UTF-8?Q??=".len());
    debug_assert!(encoded_max_len <= MAX_HEADER_FIELD_LEN);
    // Try to encode the whole string first, then continue with
    // binary search to find the maximum input length.
    let mut input_min_len = 0;
    let mut input_max_len = input.len() * 2;
    loop {
        debug_assert!(input_min_len <= input_max_len);
        debug_assert!(input.is_char_boundary(input_min_len));
        debug_assert!(input_max_len >= input.len() || input.is_char_boundary(input_max_len));
        let mut input_len = input_min_len + (input_max_len - input_min_len) / 2;
        while !input.is_char_boundary(input_len) {
            input_len = input_len - 1;
        }
        let encoded = format!(
            "=?UTF-8?Q?{}?=",
            quoted_printable::encode_to_str(input[..input_len].as_bytes())
        );
        if encoded.len() <= encoded_max_len {
            if input_len == input_min_len {
                return (encoded, input_len);
            } else {
                // adjust lower bound and continue with binary search
                input_min_len = input_len;
            }
        } else {
            debug_assert!(input_min_len < input_len);
            // adjust upper bound and continue with binary search
            input_max_len = input_len;
        }
    }
}

fn encode_header_field(name: &str, input: &str) -> String {
    let mut prefix_len = name.len() + 1;
    let mut encoded_output = String::with_capacity(prefix_len + input.len() * 2);
    encoded_output.push_str(name);
    encoded_output.push(':');
    let mut input_len = 0;
    while input_len < input.len() {
        if input_len > 0 {
            // append line break and continuation
            encoded_output.push_str(LINE_BREAK);
            encoded_output.push(' ');
            prefix_len = 1;
        }
        let (encoded_part, input_part_len) =
            encode_header_field_partially(&input[input_len..], MAX_HEADER_FIELD_LEN - prefix_len);
        debug_assert!(!encoded_part.is_empty());
        debug_assert!(input_part_len > 0);
        encoded_output.push_str(&encoded_part);
        input_len = input_len + input_part_len;
    }
    encoded_output
}

pub fn create(to: &[String], subject: &str, body: &str) -> Result<String> {
    let to: Vec<_> = to
        .into_iter()
        .filter(|m| is_valid_email(m))
        .cloned()
        .collect();

    if to.is_empty() {
        return Err(Error::new(
            ErrorKind::Other,
            "No valid email adresses specified",
        ));
    }

    let now = Local::now();

    let email = format!(
        "Date:{date}\r\n\
         From:{from}\r\n\
         To:{to}\r\n\
         {subject_header}\r\n\
         MIME-Version:1.0\r\n\
         Content-Type:text/plain;charset=utf-8\r\n\r\n\
         {body}",
        date = now.to_rfc2822(),
        from = FROM_ADDRESS,
        to = to.join(","),
        subject_header = encode_header_field("Subject", &subject),
        body = body
    );

    debug!("composed email: {}", &email);

    Ok(email)
}

#[cfg(all(not(test), feature = "email"))]
pub mod sendmail {
    use super::*;
    use std::io::prelude::*;
    use std::process::{Command, Stdio};

    pub fn send(mail: &str) -> Result<()> {
        let mut child = Command::new("sendmail")
            .arg("-t")
            .stdin(Stdio::piped())
            .spawn()?;
        child
            .stdin
            .as_mut()
            .ok_or_else(|| Error::new(ErrorKind::Other, "Could not get stdin"))?
            .write_all(mail.as_bytes())?;
        child.wait_with_output()?;
        Ok(())
    }
}

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

    #[test]
    fn create_simple_mail() {
        let mail = create(
            &vec!["mail@test.org".into()],
            "My veeeeerrrrryyyyy looooonnnnnggggg Subject with äöüÄÖÜß Umlaute and even more characters that are distributed onto multiple lines",
            "Hello Mail",
        ).unwrap();
        let expected =
            "From:\"Karte von morgen\" <no-reply@kartevonmorgen.org>\r\n\
             To:mail@test.org\r\n\
             Subject:=?UTF-8?Q?My veeeeerrrrryyyyy looooonnnnnggggg Subject with =C3=A4?=\r\n \
             =?UTF-8?Q?=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F Umlaute and even more char?=\r\n \
             =?UTF-8?Q?acters that are distributed onto multiple lines?=\r\n\
             MIME-Version:1.0\r\n\
             Content-Type:text/plain;charset=utf-8\r\n\r\n\
             Hello Mail";
        assert!(mail.contains(expected));
    }

    #[test]
    fn check_addresses() {
        assert!(create(&vec![], "foo", "bar").is_err());
        assert!(create(&vec!["not-valid".into()], "foo", "bar").is_err());
    }
}
<|endoftext|>


<commit_before>#![allow(unsafe_code)]
#![allow(unused)]

use std::{
    alloc::{alloc_zeroed, dealloc, Layout},
    convert::{TryFrom, TryInto},
    mem::{align_of, size_of},
    num::NonZeroU64,
    ops::{Deref, DerefMut, Index, IndexMut},
};

const ALIGNMENT: usize = align_of::<Header>();

// allocates space for a header struct at the beginning.
fn aligned_boxed_slice(size: usize) -> Box<[u8]> {
    let size = size + size_of::<Header>();
    let layout = Layout::from_size_align(size, ALIGNMENT).unwrap();

    unsafe {
        let ptr = alloc_zeroed(layout);
        let fat_ptr = fatten(ptr, size);
        let ret = Box::from_raw(fat_ptr);
        assert_eq!(ret.len(), size);
        ret
    }
}

/// <https://users.rust-lang.org/t/construct-fat-pointer-to-struct/29198/9>
#[allow(trivial_casts)]
#[inline]
fn fatten(data: *const u8, len: usize) -> *mut [u8] {
    // Requirements of slice::from_raw_parts.
    assert!(!data.is_null());
    assert!(isize::try_from(len).is_ok());

    let slice = unsafe { core::slice::from_raw_parts(data as *const (), len) };
    slice as *const [()] as *mut _
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub(crate) struct Header {
    // NB always lay out fields from largest to smallest
    // to properly pack the struct
    pub next: Option<NonZeroU64>,
    pub merging_child: Option<NonZeroU64>,
    //fixed_key_length: Option<NonZeroU64>,
    pub children: u16,
    pub prefix_len: u8,
    pub merging: bool,
    pub is_index: bool,
}

pub(crate) struct InlineRecords(Box<[u8]>);

impl Deref for InlineRecords {
    type Target = Header;

    fn deref(&self) -> &Header {
        self.header()
    }
}

impl DerefMut for InlineRecords {
    fn deref_mut(&mut self) -> &mut Header {
        self.header_mut()
    }
}

impl Index<usize> for InlineRecords {
    type Output = [u8];

    // returns the bytes for an item's length + the item itself +
    fn index(&self, idx: usize) -> &[u8] {
        assert!(idx <= usize::from(self.children));
        let offsets_start = size_of::<Header>();
        let u64_size = size_of::<u64>();
        let offsets_end =
            offsets_start + (usize::from(self.children) * u64_size);
        let offsets = &self.0[offsets_start..offsets_end];
        let offset = &offsets[u64_size * idx..u64_size * (idx + 1)];

        let offset_slice = &offset[..u64_size];

        let offset =
            u64::from_le_bytes(offset_slice.try_into().unwrap()) as usize;

        let length_key_and_value = &self.0[offsets_end + offset..];

        let length_buf = &length_key_and_value[..u64_size];
        let length =
            u64::from_le_bytes(length_buf.try_into().unwrap()) as usize;

        let length =
            u64::from_le_bytes(offset_slice.try_into().unwrap()) as usize;

        let start = offset + u64_size;
        let end = start + length + u64_size;

        &length_key_and_value[start..end]
    }
}

impl InlineRecords {
    fn new(
        hi: &[u8],
        lo: &[u8],
        prefix_len: u8,
        items: &[(&[u8], u64)],
    ) -> InlineRecords {
        let offsets_and_lengths_size =
            (2 * size_of::<u64>()) * (2 + items.len());
        let keys_and_values_size =
            items.iter().map(|(k, _pid)| k.len()).sum::<usize>()
                + size_of::<u64>() * (2 + items.len());

        let boxed_slice = aligned_boxed_slice(
            offsets_and_lengths_size + keys_and_values_size,
        );

        let mut ret = InlineRecords(boxed_slice);
        ret.next = None;
        ret.merging_child = None;
        ret.children = u16::try_from(items.len()).unwrap();
        ret.prefix_len = prefix_len;
        ret.merging = false;
        ret.is_index = true;

        let data_buf = &mut ret.0[size_of::<Header>()..];
        let (offsets, lengths_keys_and_values) =
            data_buf.split_at_mut(offsets_and_lengths_size);

        let bounds = [(lo, 0), (hi, 0)];
        let iter = bounds.iter().chain(items.into_iter());

        let u64_size = size_of::<u64>();

        let mut kv_cursor = 0_usize;
        for (idx, (key, pid)) in iter.enumerate() {
            let offsets_cursor = idx * u64_size;
            offsets[offsets_cursor..offsets_cursor + u64_size]
                .copy_from_slice(&kv_cursor.to_le_bytes());

            lengths_keys_and_values[kv_cursor..kv_cursor + u64_size]
                .copy_from_slice(&(key.len() as u64).to_le_bytes());
            kv_cursor += u64_size;

            lengths_keys_and_values[kv_cursor..kv_cursor + key.len()]
                .copy_from_slice(key);
            kv_cursor += key.len();

            lengths_keys_and_values[kv_cursor..kv_cursor + u64_size]
                .copy_from_slice(&pid.to_le_bytes());
            kv_cursor += u64_size;
        }

        ret
    }

    fn header(&self) -> &Header {
        unsafe { &*(self.0.as_ptr() as *mut Header) }
    }

    fn header_mut(&mut self) -> &mut Header {
        unsafe { &mut *(self.0.as_ptr() as *mut Header) }
    }

    fn len(&self) -> usize {
        usize::from(self.children)
    }

    fn find(&self, key: &[u8]) -> Result<usize, usize> {
        todo!()
    }

    fn insert(&mut self, key: &[u8], pid: u64) {
        match self.find(&key[usize::from(self.prefix_len)..]) {
            Ok(offset) => {
                if self.is_index {
                    panic!("already contained key being merged into index");
                }
                todo!()
            }
            Err(prospective_offset) => {
                todo!()
            }
        }
    }

    fn get_lub(&self, key: &[u8]) -> u64 {
        assert!(key >= self.lo());
        todo!()
    }

    fn lo(&self) -> &[u8] {
        let ret = &self[0];
        &ret[..ret.len() - size_of::<u64>()]
    }

    fn hi(&self) -> &[u8] {
        let ret = &self[1];
        &ret[..ret.len() - size_of::<u64>()]
    }
}

fn varint_size(int: u64) -> u64 {
    if int <= 240 {
        1
    } else if int <= 2287 {
        2
    } else if int <= 67823 {
        3
    } else if int <= 0x00FF_FFFF {
        4
    } else if int <= 0xFFFF_FFFF {
        5
    } else if int <= 0x00FF_FFFF_FFFF {
        6
    } else if int <= 0xFFFF_FFFF_FFFF {
        7
    } else if int <= 0x00FF_FFFF_FFFF_FFFF {
        8
    } else {
        9
    }
}

fn serialize_varint_into(int: u64, buf: &mut [u8]) {
    if int <= 240 {
        buf[0] = u8::try_from(int).unwrap();
    } else if int <= 2287 {
        buf[0] = u8::try_from((int - 240) / 256 + 241).unwrap();
        buf[1] = u8::try_from((int - 240) % 256).unwrap();
    } else if int <= 67823 {
        buf[0] = 249;
        buf[1] = u8::try_from((int - 2288) / 256).unwrap();
        buf[2] = u8::try_from((int - 2288) % 256).unwrap();
    } else if int <= 0x00FF_FFFF {
        buf[0] = 250;
        let bytes = int.to_le_bytes();
        buf[1..4].copy_from_slice(&bytes[..3]);
    } else if int <= 0xFFFF_FFFF {
        buf[0] = 251;
        let bytes = int.to_le_bytes();
        buf[1..5].copy_from_slice(&bytes[..4]);
    } else if int <= 0x00FF_FFFF_FFFF {
        buf[0] = 252;
        let bytes = int.to_le_bytes();
        buf[1..6].copy_from_slice(&bytes[..5]);
    } else if int <= 0xFFFF_FFFF_FFFF {
        buf[0] = 253;
        let bytes = int.to_le_bytes();
        buf[1..7].copy_from_slice(&bytes[..6]);
    } else if int <= 0x00FF_FFFF_FFFF_FFFF {
        buf[0] = 254;
        let bytes = int.to_le_bytes();
        buf[1..8].copy_from_slice(&bytes[..7]);
    } else {
        buf[0] = 255;
        let bytes = int.to_le_bytes();
        buf[1..9].copy_from_slice(&bytes[..8]);
    };
}

fn deserialize_varint(buf: &[u8]) -> crate::Result<u64> {
    if buf.is_empty() {
        return Err(crate::Error::corruption(None));
    }
    let res = match buf[0] {
        0..=240 => u64::from(buf[0]),
        241..=248 => 240 + 256 * (u64::from(buf[0]) - 241) + u64::from(buf[1]),
        249 => 2288 + 256 * u64::from(buf[1]) + u64::from(buf[2]),
        other => {
            let sz = other as usize - 247;
            let mut aligned = [0; 8];
            aligned[..sz].copy_from_slice(&buf[1..=sz]);
            u64::from_le_bytes(aligned)
        }
    };
    Ok(res)
}

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

    #[test]
    fn simple() {
        let mut ir = InlineRecords::new();
        let header: &mut Header = ir.header_mut();
        header.next = Some(NonZeroU64::new(5).unwrap());
        header.is_index = true;
        dbg!(header);
        println!("ir: {:?}", ir.0);
    }
}
<commit_msg>Fill in more gaps in the inline record work<commit_after>#![allow(unsafe_code)]
#![allow(unused)]

use std::{
    alloc::{alloc_zeroed, dealloc, Layout},
    convert::{TryFrom, TryInto},
    fmt,
    mem::{align_of, size_of, ManuallyDrop},
    num::NonZeroU64,
    ops::{Deref, DerefMut, Index, IndexMut},
};

const ALIGNMENT: usize = align_of::<Header>();
const U64_SZ: usize = size_of::<u64>();

// allocates space for a header struct at the beginning.
fn aligned_boxed_slice(size: usize) -> Box<[u8]> {
    let size = size + size_of::<Header>();
    let layout = Layout::from_size_align(size, ALIGNMENT).unwrap();

    unsafe {
        let ptr = alloc_zeroed(layout);
        let fat_ptr = fatten(ptr, size);
        let ret = Box::from_raw(fat_ptr);
        assert_eq!(ret.len(), size);
        ret
    }
}

/// <https://users.rust-lang.org/t/construct-fat-pointer-to-struct/29198/9>
#[allow(trivial_casts)]
#[inline]
fn fatten(data: *const u8, len: usize) -> *mut [u8] {
    // Requirements of slice::from_raw_parts.
    assert!(!data.is_null());
    assert!(isize::try_from(len).is_ok());

    let slice = unsafe { core::slice::from_raw_parts(data as *const (), len) };
    slice as *const [()] as *mut _
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub(crate) struct Header {
    // NB always lay out fields from largest to smallest
    // to properly pack the struct
    pub next: Option<NonZeroU64>,
    pub merging_child: Option<NonZeroU64>,
    //fixed_key_length: Option<NonZeroU64>,
    pub children: u16,
    pub prefix_len: u8,
    pub merging: bool,
    pub is_index: bool,
}

pub(crate) struct InlineRecords(ManuallyDrop<Box<[u8]>>);

impl Drop for InlineRecords {
    fn drop(&mut self) {
        let box_ptr = self.0.as_mut_ptr();
        let layout = Layout::from_size_align(self.0.len(), ALIGNMENT).unwrap();
        unsafe {
            dealloc(box_ptr, layout);
        }
    }
}

impl Deref for InlineRecords {
    type Target = Header;

    fn deref(&self) -> &Header {
        self.header()
    }
}

impl fmt::Debug for InlineRecords {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("InlineRecords")
            .field("header", self.header())
            .field("lo", &self.lo())
            .field("hi", &self.hi())
            .field("items", &self.iter().collect::<crate::Map<_, _>>())
            .finish()
    }
}

impl DerefMut for InlineRecords {
    fn deref_mut(&mut self) -> &mut Header {
        self.header_mut()
    }
}

impl InlineRecords {
    fn new(
        hi: &[u8],
        lo: &[u8],
        prefix_len: u8,
        items: &[(&[u8], u64)],
    ) -> InlineRecords {
        let offsets_and_lengths_size =
            (2 * size_of::<u64>()) * (2 + items.len());
        let keys_and_values_size =
            items.iter().map(|(k, _pid)| k.len()).sum::<usize>()
                + size_of::<u64>() * (2 + items.len());

        let boxed_slice = aligned_boxed_slice(
            offsets_and_lengths_size + keys_and_values_size,
        );

        let mut ret = InlineRecords(ManuallyDrop::new(boxed_slice));
        ret.next = None;
        ret.merging_child = None;
        ret.children = u16::try_from(items.len()).unwrap();
        ret.prefix_len = prefix_len;
        ret.merging = false;
        ret.is_index = true;

        let data_buf = &mut ret.0[size_of::<Header>()..];
        let (offsets, lengths_keys_and_values) =
            data_buf.split_at_mut(offsets_and_lengths_size);

        let bounds = [(lo, 0), (hi, 0)];
        let iter = bounds.iter().chain(items.into_iter());

        let mut kv_cursor = 0_usize;
        for (idx, (key, pid)) in iter.enumerate() {
            let offsets_cursor = idx * U64_SZ;
            offsets[offsets_cursor..offsets_cursor + U64_SZ]
                .copy_from_slice(&kv_cursor.to_le_bytes());

            lengths_keys_and_values[kv_cursor..kv_cursor + U64_SZ]
                .copy_from_slice(&(key.len() as u64).to_le_bytes());
            kv_cursor += U64_SZ;

            lengths_keys_and_values[kv_cursor..kv_cursor + key.len()]
                .copy_from_slice(key);
            kv_cursor += key.len();

            lengths_keys_and_values[kv_cursor..kv_cursor + U64_SZ]
                .copy_from_slice(&pid.to_le_bytes());
            kv_cursor += U64_SZ;
        }

        ret
    }

    fn header(&self) -> &Header {
        unsafe { &*(self.0.as_ptr() as *mut Header) }
    }

    fn header_mut(&mut self) -> &mut Header {
        unsafe { &mut *(self.0.as_mut_ptr() as *mut Header) }
    }

    fn len(&self) -> usize {
        usize::from(self.children)
    }

    fn find(&self, key: &[u8]) -> Result<usize, usize> {
        todo!()
    }

    fn insert(&mut self, key: &[u8], pid: u64) {
        match self.find(&key[usize::from(self.prefix_len)..]) {
            Ok(offset) => {
                if self.is_index {
                    panic!("already contained key being merged into index");
                }
                todo!()
            }
            Err(prospective_offset) => {
                todo!()
            }
        }
    }

    fn get_lub(&self, key: &[u8]) -> u64 {
        assert!(key >= self.lo());
        todo!()
    }

    fn iter(&self) -> impl Iterator<Item = (&[u8], u64)> {
        (0..usize::from(self.children)).map(move |idx| self.index(idx))
    }

    fn lo(&self) -> &[u8] {
        self.index(0).0
    }

    fn hi(&self) -> &[u8] {
        self.index(1).0
    }

    fn index(&self, idx: usize) -> (&[u8], u64) {
        assert!(idx < usize::from(self.children));

        let raw = self.index_raw(idx);

        let pivot = raw.len() - U64_SZ;

        let (key, pid_bytes) = raw.split_at(pivot);

        (key, u64::from_le_bytes(pid_bytes.try_into().unwrap()))
    }

    fn index_raw(&self, idx: usize) -> &[u8] {
        assert!(idx <= usize::from(self.children));
        let offsets_start = size_of::<Header>();
        let offsets_end = offsets_start + (usize::from(self.children) * U64_SZ);
        let offsets = &self.0[offsets_start..offsets_end];
        let offset = &offsets[U64_SZ * idx..U64_SZ * (idx + 1)];

        let offset_slice = &offset[..U64_SZ];

        let offset =
            u64::from_le_bytes(offset_slice.try_into().unwrap()) as usize;

        let length_key_and_value = &self.0[offsets_end + offset..];

        let length_buf = &length_key_and_value[..U64_SZ];
        let length =
            u64::from_le_bytes(length_buf.try_into().unwrap()) as usize;

        let length =
            u64::from_le_bytes(offset_slice.try_into().unwrap()) as usize;

        let start = offset + U64_SZ;
        let end = start + length + U64_SZ;

        &length_key_and_value[start..end]
    }
}

fn varint_size(int: u64) -> u64 {
    if int <= 240 {
        1
    } else if int <= 2287 {
        2
    } else if int <= 67823 {
        3
    } else if int <= 0x00FF_FFFF {
        4
    } else if int <= 0xFFFF_FFFF {
        5
    } else if int <= 0x00FF_FFFF_FFFF {
        6
    } else if int <= 0xFFFF_FFFF_FFFF {
        7
    } else if int <= 0x00FF_FFFF_FFFF_FFFF {
        8
    } else {
        9
    }
}

fn serialize_varint_into(int: u64, buf: &mut [u8]) {
    if int <= 240 {
        buf[0] = u8::try_from(int).unwrap();
    } else if int <= 2287 {
        buf[0] = u8::try_from((int - 240) / 256 + 241).unwrap();
        buf[1] = u8::try_from((int - 240) % 256).unwrap();
    } else if int <= 67823 {
        buf[0] = 249;
        buf[1] = u8::try_from((int - 2288) / 256).unwrap();
        buf[2] = u8::try_from((int - 2288) % 256).unwrap();
    } else if int <= 0x00FF_FFFF {
        buf[0] = 250;
        let bytes = int.to_le_bytes();
        buf[1..4].copy_from_slice(&bytes[..3]);
    } else if int <= 0xFFFF_FFFF {
        buf[0] = 251;
        let bytes = int.to_le_bytes();
        buf[1..5].copy_from_slice(&bytes[..4]);
    } else if int <= 0x00FF_FFFF_FFFF {
        buf[0] = 252;
        let bytes = int.to_le_bytes();
        buf[1..6].copy_from_slice(&bytes[..5]);
    } else if int <= 0xFFFF_FFFF_FFFF {
        buf[0] = 253;
        let bytes = int.to_le_bytes();
        buf[1..7].copy_from_slice(&bytes[..6]);
    } else if int <= 0x00FF_FFFF_FFFF_FFFF {
        buf[0] = 254;
        let bytes = int.to_le_bytes();
        buf[1..8].copy_from_slice(&bytes[..7]);
    } else {
        buf[0] = 255;
        let bytes = int.to_le_bytes();
        buf[1..9].copy_from_slice(&bytes[..8]);
    };
}

fn deserialize_varint(buf: &[u8]) -> crate::Result<u64> {
    if buf.is_empty() {
        return Err(crate::Error::corruption(None));
    }
    let res = match buf[0] {
        0..=240 => u64::from(buf[0]),
        241..=248 => 240 + 256 * (u64::from(buf[0]) - 241) + u64::from(buf[1]),
        249 => 2288 + 256 * u64::from(buf[1]) + u64::from(buf[2]),
        other => {
            let sz = other as usize - 247;
            let mut aligned = [0; 8];
            aligned[..sz].copy_from_slice(&buf[1..=sz]);
            u64::from_le_bytes(aligned)
        }
    };
    Ok(res)
}

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

    #[test]
    fn simple() {
        let mut ir = InlineRecords::new(&[], &[], 0, &[]);
        let header: &mut Header = ir.header_mut();
        header.next = Some(NonZeroU64::new(5).unwrap());
        header.is_index = true;
        dbg!(header);
        println!("ir: {:?}", ir);
    }
}
<|endoftext|>


<commit_before>use err_derive::Error;

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug, Error)]
pub enum Error {
    #[error(
        display = "Unable to find binary to execute. Run `monger get {}` and try again if you're sure the version and binary name are correct",
        version
    )]
    BinaryNotFound { binary: String, version: String },

    #[error(display = "`{}` command failed", command)]
    FailedSubprocess {
        command: String,
        exit_code: Option<i32>,
    },

    #[error(display = "An HTTP error occurred: {}", inner)]
    Http { inner: reqwest::Error },

    #[error(
        display = "HTML response from {} did not match expected structure",
        url
    )]
    InvalidHtml { url: String },

    #[error(display = "MongoDB version {} does not exist", version)]
    InvalidVersion { version: String },

    #[error(display = "An I/O error occurred: {}", inner)]
    Io { inner: std::io::Error },

    #[error(display = "Unable to determine the OS release version")]
    OsRelease { inner: rs_release::OsReleaseError },

    #[error(display = "Unable to parse semantic version")]
    SemVer { inner: semver::SemVerError },

    #[error(display = "Unable to convert HTTP header to string: {}", inner)]
    ToStr { inner: reqwest::header::ToStrError },

    #[error(display = "Unable to find home directory")]
    UnknownHomeDirectory,

    #[error(display = "Unable to identify operating system")]
    UnknownOs,

    #[error(display = "{} is unsupported", os_name)]
    UnsupportedOs { os_name: String },

    #[error(display = "Unable to find version {}", version)]
    VersionNotFound { version: String },
}

impl From<reqwest::Error> for Error {
    fn from(err: reqwest::Error) -> Self {
        Self::Http { inner: err }
    }
}

impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Self {
        Self::Io { inner: err }
    }
}

impl From<rs_release::OsReleaseError> for Error {
    fn from(err: rs_release::OsReleaseError) -> Self {
        Self::OsRelease { inner: err }
    }
}

impl From<semver::SemVerError> for Error {
    fn from(err: semver::SemVerError) -> Self {
        Self::SemVer { inner: err }
    }
}

impl From<reqwest::header::ToStrError> for Error {
    fn from(err: reqwest::header::ToStrError) -> Self {
        Self::ToStr { inner: err }
    }
}
<commit_msg>update err-derive<commit_after>use err_derive::Error;

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug, Error)]
pub enum Error {
    #[error(
        display = "Unable to find binary to execute. Run `monger get {}` and try again if you're \
                   sure the version and binary name are correct",
        version
    )]
    BinaryNotFound { binary: String, version: String },

    #[error(display = "`{}` command failed", command)]
    FailedSubprocess {
        command: String,
        exit_code: Option<i32>,
    },

    #[error(display = "An HTTP error occurred: {}", inner)]
    Http {
        #[error(cause)]
        inner: reqwest::Error,
    },

    #[error(
        display = "HTML response from {} did not match expected structure",
        url
    )]
    InvalidHtml { url: String },

    #[error(display = "MongoDB version {} does not exist", version)]
    InvalidVersion { version: String },

    #[error(display = "An I/O error occurred: {}", inner)]
    Io {
        #[error(cause)]
        inner: std::io::Error,
    },

    #[error(display = "Unable to determine the OS release version")]
    OsRelease {
        #[error(cause)]
        inner: rs_release::OsReleaseError,
    },

    #[error(display = "Unable to parse semantic version")]
    SemVer {
        #[error(cause)]
        inner: semver::SemVerError,
    },

    #[error(display = "Unable to convert HTTP header to string: {}", inner)]
    ToStr {
        #[error(cause)]
        inner: reqwest::header::ToStrError,
    },

    #[error(display = "Unable to find home directory")]
    UnknownHomeDirectory,

    #[error(display = "Unable to identify operating system")]
    UnknownOs,

    #[error(display = "{} is unsupported", os_name)]
    UnsupportedOs { os_name: String },

    #[error(display = "Unable to find version {}", version)]
    VersionNotFound { version: String },
}

macro_rules! define_error_from {
    ($ext:ty, $var:ident) => {
        impl From<$ext> for Error {
            fn from(err: $ext) -> Self {
                Error::$var { inner: err }
            }
        }
    };
}

define_error_from!(reqwest::Error, Http);
define_error_from!(std::io::Error, Io);
define_error_from!(rs_release::OsReleaseError, OsRelease);
define_error_from!(semver::SemVerError, SemVer);
define_error_from!(reqwest::header::ToStrError, ToStr);
<|endoftext|>


<commit_before>#![feature(test)]
extern crate test;
extern crate itertools;

use itertools::Stride;

use itertools::{Zip, ZipTrusted};

use std::iter::repeat;
use std::marker::PhantomData;

#[bench]
fn slice_iter(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in xs.as_slice().iter() {
        test::black_box(elt);
    })
}

#[bench]
fn slice_iter_rev(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in xs.as_slice().iter().rev() {
        test::black_box(elt);
    })
}

#[bench]
fn stride_iter(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in Stride::from_slice(xs.as_slice(), 1) {
        test::black_box(elt);
    })
}

#[bench]
fn stride_iter_rev(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in Stride::from_slice(xs.as_slice(), 1).rev() {
        test::black_box(elt);
    })
}

#[derive(Copy)]
struct ZipSlices<'a, T: 'a, U :'a>
{
    t_ptr: *const T,
    t_end: *const T,
    u_ptr: *const U,
    mark: PhantomData<&'a (T, U)>,
}

impl<'a, T, U> ZipSlices<'a, T, U>
{
    pub fn new(t: &'a [T], u: &'a [U]) -> Self
    {
        assert!(::std::mem::size_of::<T>() != 0);
        assert!(::std::mem::size_of::<U>() != 0);
        let minl = std::cmp::min(t.len(), u.len());
        let end_ptr = unsafe {
            t.as_ptr().offset(minl as isize)
        };
        ZipSlices {
            t_ptr: t.as_ptr(),
            t_end: end_ptr,
            u_ptr: u.as_ptr(),
            mark: PhantomData,
        }
    }
}

impl<'a, T, U> Iterator for ZipSlices<'a, T, U>
{
    type Item = (&'a T, &'a U);

    #[inline]
    fn next(&mut self) -> Option<(&'a T, &'a U)>
    {
        if self.t_ptr == self.t_end {
            return None
        }
        let t_elt: &T;
        let u_elt: &U;
        unsafe {
            t_elt = ::std::mem::transmute(self.t_ptr);
            self.t_ptr = self.t_ptr.offset(1);
            u_elt = ::std::mem::transmute(self.u_ptr);
            self.u_ptr = self.u_ptr.offset(1);
        }
        Some((t_elt, u_elt))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>)
    {
        let len = self.t_end as usize - self.t_ptr as usize;
        (len, Some(len))
    }
}

#[bench]
fn zip_slices_default_zip(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];

    b.iter(|| for (&x, &y) in xs.iter().zip(ys.iter()) {
        test::black_box(x);
        test::black_box(y);
    })
}

#[bench]
fn zip_slices_default_zip3(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let zs = vec![0; 766];

    b.iter(|| for ((&x, &y), &z) in xs.iter().zip(ys.iter()).zip(zs.iter()) {
        test::black_box(x);
        test::black_box(y);
        test::black_box(z);
    })
}

#[bench]
fn zip_slices_ziptuple(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];

    b.iter(|| for (&x, &y) in Zip::new((xs.iter(), ys.iter())) {
        test::black_box(x);
        test::black_box(y);
    })
}

#[bench]
fn zipslices(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];

    b.iter(|| for (&x, &y) in ZipSlices::new(&xs, &ys) {
        test::black_box(x);
        test::black_box(y);
    })
}

#[bench]
fn ziptrusted(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];

    b.iter(|| for (&x, &y) in ZipTrusted::new((xs.iter(), ys.iter())) {
        test::black_box(x);
        test::black_box(y);
    })
}

#[bench]
fn ziptrusted3(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let zs = vec![0; 766];

    b.iter(|| for (&x, &y, &z) in ZipTrusted::new((xs.iter(), ys.iter(), zs.iter())) {
        test::black_box(x);
        test::black_box(y);
        test::black_box(z);
    })
}

#[bench]
fn zip_loop(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];

    b.iter(|| {
        let len = ::std::cmp::min(xs.len(), ys.len());
        for i in 0..len {
            unsafe {
            let x = *xs.get_unchecked(i);
            let y = *ys.get_unchecked(i);
            test::black_box(x);
            test::black_box(y);
            }
        }
    })
}

#[bench]
fn zip_loop3(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let zs = vec![0; 766];

    b.iter(|| {
        let len = ::std::cmp::min(xs.len(), ::std::cmp::min(ys.len(), zs.len()));
        for i in 0..len {
            unsafe {
            let x = *xs.get_unchecked(i);
            let y = *ys.get_unchecked(i);
            let z = *zs.get_unchecked(i);
            test::black_box(x);
            test::black_box(y);
            test::black_box(z);
            }
        }
    })
}
<commit_msg>Remove as_slice calls from the benchmarks.<commit_after>#![feature(test)]
extern crate test;
extern crate itertools;

use itertools::Stride;

use itertools::{Zip, ZipTrusted};

use std::iter::repeat;
use std::marker::PhantomData;

#[bench]
fn slice_iter(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in xs.iter() {
        test::black_box(elt);
    })
}

#[bench]
fn slice_iter_rev(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in xs.iter().rev() {
        test::black_box(elt);
    })
}

#[bench]
fn stride_iter(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in Stride::from_slice(&xs, 1) {
        test::black_box(elt);
    })
}

#[bench]
fn stride_iter_rev(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in Stride::from_slice(&xs, 1).rev() {
        test::black_box(elt);
    })
}

#[derive(Copy)]
struct ZipSlices<'a, T: 'a, U :'a>
{
    t_ptr: *const T,
    t_end: *const T,
    u_ptr: *const U,
    mark: PhantomData<&'a (T, U)>,
}

impl<'a, T, U> ZipSlices<'a, T, U>
{
    pub fn new(t: &'a [T], u: &'a [U]) -> Self
    {
        assert!(::std::mem::size_of::<T>() != 0);
        assert!(::std::mem::size_of::<U>() != 0);
        let minl = std::cmp::min(t.len(), u.len());
        let end_ptr = unsafe {
            t.as_ptr().offset(minl as isize)
        };
        ZipSlices {
            t_ptr: t.as_ptr(),
            t_end: end_ptr,
            u_ptr: u.as_ptr(),
            mark: PhantomData,
        }
    }
}

impl<'a, T, U> Iterator for ZipSlices<'a, T, U>
{
    type Item = (&'a T, &'a U);

    #[inline]
    fn next(&mut self) -> Option<(&'a T, &'a U)>
    {
        if self.t_ptr == self.t_end {
            return None
        }
        let t_elt: &T;
        let u_elt: &U;
        unsafe {
            t_elt = ::std::mem::transmute(self.t_ptr);
            self.t_ptr = self.t_ptr.offset(1);
            u_elt = ::std::mem::transmute(self.u_ptr);
            self.u_ptr = self.u_ptr.offset(1);
        }
        Some((t_elt, u_elt))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>)
    {
        let len = self.t_end as usize - self.t_ptr as usize;
        (len, Some(len))
    }
}

#[bench]
fn zip_slices_default_zip(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];

    b.iter(|| for (&x, &y) in xs.iter().zip(ys.iter()) {
        test::black_box(x);
        test::black_box(y);
    })
}

#[bench]
fn zip_slices_default_zip3(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let zs = vec![0; 766];

    b.iter(|| for ((&x, &y), &z) in xs.iter().zip(ys.iter()).zip(zs.iter()) {
        test::black_box(x);
        test::black_box(y);
        test::black_box(z);
    })
}

#[bench]
fn zip_slices_ziptuple(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];

    b.iter(|| for (&x, &y) in Zip::new((xs.iter(), ys.iter())) {
        test::black_box(x);
        test::black_box(y);
    })
}

#[bench]
fn zipslices(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];

    b.iter(|| for (&x, &y) in ZipSlices::new(&xs, &ys) {
        test::black_box(x);
        test::black_box(y);
    })
}

#[bench]
fn ziptrusted(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];

    b.iter(|| for (&x, &y) in ZipTrusted::new((xs.iter(), ys.iter())) {
        test::black_box(x);
        test::black_box(y);
    })
}

#[bench]
fn ziptrusted3(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let zs = vec![0; 766];

    b.iter(|| for (&x, &y, &z) in ZipTrusted::new((xs.iter(), ys.iter(), zs.iter())) {
        test::black_box(x);
        test::black_box(y);
        test::black_box(z);
    })
}

#[bench]
fn zip_loop(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];

    b.iter(|| {
        let len = ::std::cmp::min(xs.len(), ys.len());
        for i in 0..len {
            unsafe {
            let x = *xs.get_unchecked(i);
            let y = *ys.get_unchecked(i);
            test::black_box(x);
            test::black_box(y);
            }
        }
    })
}

#[bench]
fn zip_loop3(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let zs = vec![0; 766];

    b.iter(|| {
        let len = ::std::cmp::min(xs.len(), ::std::cmp::min(ys.len(), zs.len()));
        for i in 0..len {
            unsafe {
            let x = *xs.get_unchecked(i);
            let y = *ys.get_unchecked(i);
            let z = *zs.get_unchecked(i);
            test::black_box(x);
            test::black_box(y);
            test::black_box(z);
            }
        }
    })
}
<|endoftext|>


<commit_before>#![feature(duration)]
#![feature(thread_sleep)]

use std::fs::File;
use std::io::Read;
use std::mem::transmute;
use std::thread::sleep;
use std::time::Duration;
use std::env;

fn main() {
    let delay = match env::args().nth(1).and_then(|s| s.parse::<f32>().ok()) {
        Some(d) => 60.0 * d,
        None => {
            println!("Usage: boot-delay <minutes>");
            return;
        }
    };

    let mut buf = [0u8; 1024];
    let uptime = File::open("/proc/uptime")
        .and_then(|ref mut file| file.read(&mut buf))
        .map(|sz| {
            buf.iter()
               .position(|&c| c == 0x20)
               .and_then(|p| if p < sz {
                   unsafe { transmute::<_, &str>(&buf[..p]) }.parse::<f32>().ok()
               } else {
                   None
               }).unwrap()
        })
        .unwrap();

    if delay > uptime {
        sleep(Duration::from_secs((delay - uptime) as u64));
    }
}
<commit_msg>remove stable feature: duration<commit_after>#![feature(thread_sleep)]

use std::fs::File;
use std::io::Read;
use std::mem::transmute;
use std::thread::sleep;
use std::time::Duration;
use std::env;

fn main() {
    let delay = match env::args().nth(1).and_then(|s| s.parse::<f32>().ok()) {
        Some(d) => 60.0 * d,
        None => {
            println!("Usage: boot-delay <minutes>");
            return;
        }
    };

    let mut buf = [0u8; 1024];
    let uptime = File::open("/proc/uptime")
        .and_then(|ref mut file| file.read(&mut buf))
        .map(|sz| {
            buf.iter()
               .position(|&c| c == 0x20)
               .and_then(|p| if p < sz {
                   unsafe { transmute::<_, &str>(&buf[..p]) }.parse::<f32>().ok()
               } else {
                   None
               }).unwrap()
        })
        .unwrap();

    if delay > uptime {
        sleep(Duration::from_secs((delay - uptime) as u64));
    }
}
<|endoftext|>


<commit_before>// we have lots of arguments, cleaning this up would be a large project
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]

extern crate cargo;
extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate failure;
extern crate git2_curl;
extern crate log;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::collections::BTreeSet;

use cargo::core::shell::Shell;
use cargo::util::{self, lev_distance, CargoResult, CliResult, Config};
use cargo::util::{CliError, ProcessError};

mod cli;
mod command_prelude;
mod commands;

fn main() {
    env_logger::init();
    cargo::core::maybe_allow_nightly_features();

    let mut config = match Config::default() {
        Ok(cfg) => cfg,
        Err(e) => {
            let mut shell = Shell::new();
            cargo::exit_with_error(e.into(), &mut shell)
        }
    };

    let result = match cargo::ops::fix_maybe_exec_rustc() {
        Ok(true) => Ok(()),
        Ok(false) => {
            init_git_transports(&mut config);
            let _token = cargo::util::job::setup();
            cli::main(&mut config)
        }
        Err(e) => Err(CliError::from(e)),
    };

    match result {
        Err(e) => cargo::exit_with_error(e, &mut *config.shell()),
        Ok(()) => {}
    }
}

fn aliased_command(config: &Config, command: &str) -> CargoResult<Option<Vec<String>>> {
    let alias_name = format!("alias.{}", command);
    let mut result = Ok(None);
    match config.get_string(&alias_name) {
        Ok(value) => {
            if let Some(record) = value {
                let alias_commands = record
                    .val
                    .split_whitespace()
                    .map(|s| s.to_string())
                    .collect();
                result = Ok(Some(alias_commands));
            }
        }
        Err(_) => {
            let value = config.get_list(&alias_name)?;
            if let Some(record) = value {
                let alias_commands: Vec<String> =
                    record.val.iter().map(|s| s.0.to_string()).collect();
                result = Ok(Some(alias_commands));
            }
        }
    }
    result
}

/// List all runnable commands
fn list_commands(config: &Config) -> BTreeSet<(String, Option<String>)> {
    let prefix = "cargo-";
    let suffix = env::consts::EXE_SUFFIX;
    let mut commands = BTreeSet::new();
    for dir in search_directories(config) {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue,
        };
        for entry in entries.filter_map(|e| e.ok()) {
            let path = entry.path();
            let filename = match path.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue,
            };
            if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
                continue;
            }
            if is_executable(entry.path()) {
                let end = filename.len() - suffix.len();
                commands.insert((
                    filename[prefix.len()..end].to_string(),
                    Some(path.display().to_string()),
                ));
            }
        }
    }

    for cmd in commands::builtin() {
        commands.insert((cmd.get_name().to_string(), None));
    }

    commands
}

fn find_closest(config: &Config, cmd: &str) -> Option<String> {
    let cmds = list_commands(config);
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    cmds.into_iter()
        .map(|(c, _)| (lev_distance(&c, cmd), c))
        .filter(|&(d, _)| d < 4)
        .min_by_key(|a| a.0)
        .map(|slot| slot.1)
}

fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> CliResult {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = search_directories(config)
        .iter()
        .map(|dir| dir.join(&command_exe))
        .find(|file| is_executable(file));
    let command = match path {
        Some(command) => command,
        None => {
            let err = match find_closest(config, cmd) {
                Some(closest) => format_err!(
                    "no such subcommand: `{}`\n\n\tDid you mean `{}`?\n",
                    cmd,
                    closest
                ),
                None => format_err!("no such subcommand: `{}`", cmd),
            };
            return Err(CliError::new(err, 101));
        }
    };

    let cargo_exe = config.cargo_exe()?;
    let err = match util::process(&command)
        .env(cargo::CARGO_ENV, cargo_exe)
        .args(args)
        .exec_replace()
    {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if let Some(perr) = err.downcast_ref::<ProcessError>() {
        if let Some(code) = perr.exit.as_ref().and_then(|c| c.code()) {
            return Err(CliError::code(code));
        }
    }
    Err(CliError::new(err, 101))
}

#[cfg(unix)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path)
        .map(|metadata| metadata.is_file() && metadata.permissions().mode() & 0o111 != 0)
        .unwrap_or(false)
}
#[cfg(windows)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path)
        .map(|metadata| metadata.is_file())
        .unwrap_or(false)
}

fn search_directories(config: &Config) -> Vec<PathBuf> {
    let mut dirs = vec![config.home().clone().into_path_unlocked().join("bin")];
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if any HTTP options are specified,
    // such as proxies or custom certificate authorities. The custom
    // transport, however, is not as well battle-tested.

    match cargo::ops::needs_custom_http_transport(config) {
        Ok(true) => {}
        _ => return,
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>Resolve a unnecessary_mut_passed lint warning<commit_after>// we have lots of arguments, cleaning this up would be a large project
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]

extern crate cargo;
extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate failure;
extern crate git2_curl;
extern crate log;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::collections::BTreeSet;

use cargo::core::shell::Shell;
use cargo::util::{self, lev_distance, CargoResult, CliResult, Config};
use cargo::util::{CliError, ProcessError};

mod cli;
mod command_prelude;
mod commands;

fn main() {
    env_logger::init();
    cargo::core::maybe_allow_nightly_features();

    let mut config = match Config::default() {
        Ok(cfg) => cfg,
        Err(e) => {
            let mut shell = Shell::new();
            cargo::exit_with_error(e.into(), &mut shell)
        }
    };

    let result = match cargo::ops::fix_maybe_exec_rustc() {
        Ok(true) => Ok(()),
        Ok(false) => {
            init_git_transports(&config);
            let _token = cargo::util::job::setup();
            cli::main(&mut config)
        }
        Err(e) => Err(CliError::from(e)),
    };

    match result {
        Err(e) => cargo::exit_with_error(e, &mut *config.shell()),
        Ok(()) => {}
    }
}

fn aliased_command(config: &Config, command: &str) -> CargoResult<Option<Vec<String>>> {
    let alias_name = format!("alias.{}", command);
    let mut result = Ok(None);
    match config.get_string(&alias_name) {
        Ok(value) => {
            if let Some(record) = value {
                let alias_commands = record
                    .val
                    .split_whitespace()
                    .map(|s| s.to_string())
                    .collect();
                result = Ok(Some(alias_commands));
            }
        }
        Err(_) => {
            let value = config.get_list(&alias_name)?;
            if let Some(record) = value {
                let alias_commands: Vec<String> =
                    record.val.iter().map(|s| s.0.to_string()).collect();
                result = Ok(Some(alias_commands));
            }
        }
    }
    result
}

/// List all runnable commands
fn list_commands(config: &Config) -> BTreeSet<(String, Option<String>)> {
    let prefix = "cargo-";
    let suffix = env::consts::EXE_SUFFIX;
    let mut commands = BTreeSet::new();
    for dir in search_directories(config) {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue,
        };
        for entry in entries.filter_map(|e| e.ok()) {
            let path = entry.path();
            let filename = match path.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue,
            };
            if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
                continue;
            }
            if is_executable(entry.path()) {
                let end = filename.len() - suffix.len();
                commands.insert((
                    filename[prefix.len()..end].to_string(),
                    Some(path.display().to_string()),
                ));
            }
        }
    }

    for cmd in commands::builtin() {
        commands.insert((cmd.get_name().to_string(), None));
    }

    commands
}

fn find_closest(config: &Config, cmd: &str) -> Option<String> {
    let cmds = list_commands(config);
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    cmds.into_iter()
        .map(|(c, _)| (lev_distance(&c, cmd), c))
        .filter(|&(d, _)| d < 4)
        .min_by_key(|a| a.0)
        .map(|slot| slot.1)
}

fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> CliResult {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = search_directories(config)
        .iter()
        .map(|dir| dir.join(&command_exe))
        .find(|file| is_executable(file));
    let command = match path {
        Some(command) => command,
        None => {
            let err = match find_closest(config, cmd) {
                Some(closest) => format_err!(
                    "no such subcommand: `{}`\n\n\tDid you mean `{}`?\n",
                    cmd,
                    closest
                ),
                None => format_err!("no such subcommand: `{}`", cmd),
            };
            return Err(CliError::new(err, 101));
        }
    };

    let cargo_exe = config.cargo_exe()?;
    let err = match util::process(&command)
        .env(cargo::CARGO_ENV, cargo_exe)
        .args(args)
        .exec_replace()
    {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if let Some(perr) = err.downcast_ref::<ProcessError>() {
        if let Some(code) = perr.exit.as_ref().and_then(|c| c.code()) {
            return Err(CliError::code(code));
        }
    }
    Err(CliError::new(err, 101))
}

#[cfg(unix)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path)
        .map(|metadata| metadata.is_file() && metadata.permissions().mode() & 0o111 != 0)
        .unwrap_or(false)
}
#[cfg(windows)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path)
        .map(|metadata| metadata.is_file())
        .unwrap_or(false)
}

fn search_directories(config: &Config) -> Vec<PathBuf> {
    let mut dirs = vec![config.home().clone().into_path_unlocked().join("bin")];
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if any HTTP options are specified,
    // such as proxies or custom certificate authorities. The custom
    // transport, however, is not as well battle-tested.

    match cargo::ops::needs_custom_http_transport(config) {
        Ok(true) => {}
        _ => return,
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<|endoftext|>