<commit_before>use std::alloc::alloc;
use std::alloc::dealloc;
use std::alloc::Layout;
use std::mem::size_of;
use std::ptr::null_mut;

const _PAGE_SIZE: usize = 0x1000;

pub struct _Page {
    current_page: *mut _Page,
    next_object_offset: i32,
    exclusive_pages: i32,
}

impl _Page {
    pub fn reset(&mut self) {
        unsafe {
            *(self.get_extension_page_location()) = null_mut();
        }
        self.next_object_offset = size_of::<_Page>() as i32;
        self.exclusive_pages = 0;
        self.current_page = &mut *self;
    }

    pub fn clear(&mut self) {
        self.deallocate_extensions();
        self.reset();
    }

    pub fn is_oversized(&self) -> bool {
        self.current_page.is_null()
    }

    fn get_extension_page_location(&self) -> *mut *mut _Page {
        // Convert self to page location
        let self_location = self as *const _Page as usize;

        // Advance one page size so we are past the end of our page
        let location_behind_page = (self_location + _PAGE_SIZE) as *mut *mut _Page;

        // Go back one pointer size
        unsafe { location_behind_page.offset(-1) }
    }

    fn get_next_location(&self) -> usize {
        self as *const _Page as usize + self.next_object_offset as usize
    }

    fn set_next_location(&mut self, location: usize) {
        let self_location = self as *const _Page as usize;
        self.next_object_offset = (location - self_location as usize) as i32;
    }

    fn get_next_exclusive_page_location(&self) -> *mut *mut _Page {
        unsafe {
            self.get_extension_page_location()
                .offset(-(self.exclusive_pages as isize + 1))
        }
    }

    pub fn allocate_raw(&mut self, size: usize, align: usize) -> *mut u8 {
        if self as *mut _Page != self.current_page {
            unsafe {
                // We're already known to be full, so we delegate to the current page
                let new_object = (*self.current_page).allocate_raw(size, align);

                // Possibly our current page was also full so we propagate back the new current page
                let allocating_page = _Page::get_page(new_object);
                if allocating_page != self.current_page && (!(*allocating_page).is_oversized()) {
                    self.current_page = allocating_page;
                }
                return new_object;
            }
        }

        // Try to allocate from ourselves
        let location = self.get_next_location();
        let aligned_location = (location + align - 1) & !(align - 1);
        let next_location = aligned_location + size;
        if next_location <= self.get_next_exclusive_page_location() as usize {
            self.set_next_location(next_location);
            return location as *mut u8;
        }

        // So the space did not fit.

        // Calculate gross size to decide whether we're oversized
        if size_of::<_Page>() + size + size_of::<*mut *mut _Page>() > _PAGE_SIZE {
            if self.get_next_location() >= self.get_next_exclusive_page_location() as usize {
                // Allocate an extension page and try again with it
                unsafe {
                    return (*self.allocate_extension_page()).allocate_raw(size, align);
                }
            }

            unsafe {
                // We allocate oversized objects directly.
                let memory = alloc(Layout::from_size_align_unchecked(
                    size + size_of::<_Page>(),
                    _PAGE_SIZE,
                ));

                // Initialize a _Page object at the page start
                let page = memory as *mut _Page;

                // Oversized pages have no current_page
                (*page).current_page = null_mut();

                // Set the size since we will need it when deallocating
                (*page).next_object_offset = (size % 0x100000000) as i32;
                (*page).exclusive_pages = (size / 0x100000000) as i32;

                *(self.get_next_exclusive_page_location()) = page;
                self.exclusive_pages += 1;
                return page.offset(1) as *mut u8;
            }
        }

        // So we're not oversized. Create extension page and let it allocate.
        unsafe { (*self.allocate_extension_page()).allocate_raw(size, align) }
    }

    fn allocate_extension_page(&mut self) -> *mut _Page {
        unsafe {
            let page = _Page::allocate_page();
            *(self.get_extension_page_location()) = page;
            self.current_page = page;
            &mut *page
        }
    }

    fn allocate_page() -> *mut _Page {
        unsafe {
            let page =
                alloc(Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE)) as *mut _Page;
            (*page).reset();
            page
        }
    }

    pub fn allocate_exclusive_page(&mut self) -> *mut _Page {
        unsafe {
            if self as *mut _Page != self.current_page {
                // We're already known to be full, so we delegate to the current page
                return (*self.current_page).allocate_exclusive_page();
            }

            // Check first whether we need an ordinary extension
            if self.get_next_location() as usize >= self.get_next_exclusive_page_location() as usize
            {
                // Allocate an extension page with default size
                return (*self.allocate_extension_page()).allocate_exclusive_page();
            }

            let page = _Page::allocate_page();
            *(self.get_next_exclusive_page_location()) = page;
            self.exclusive_pages += 1;
            &mut *page
        }
    }

    pub fn extend(&mut self, top: usize, size: usize) -> bool {
        if top != self.get_next_location() {
            return false;
        }

        let new_top = top + size;
        if new_top > self.get_next_exclusive_page_location() as usize {
            return false;
        }
        self.set_next_location(new_top);

        true
    }

    pub fn deallocate_extensions(&mut self) {
        let mut page: *mut _Page = self;
        unsafe {
            while !page.is_null() {
                let extension_pointer = (*page).get_extension_page_location();
                for i in 1..(*page).exclusive_pages {
                    let mut exclusive_page = &mut **(extension_pointer.offset(-(i as isize)));
                    if !exclusive_page.is_oversized() {
                        exclusive_page.deallocate_extensions();
                    }
                    exclusive_page.forget();
                }

                if page != self as *mut _Page {
                    (*page).forget();
                }

                page = *extension_pointer;
            }
        }
    }

    pub fn forget(&self) {
        let size = if self.current_page == null_mut() {
            self.next_object_offset as usize + self.exclusive_pages as usize * 0x100000000
        } else {
            _PAGE_SIZE
        };
        unsafe {
            dealloc(
                self as *const _Page as *mut u8,
                Layout::from_size_align_unchecked(size, _PAGE_SIZE),
            )
        }
    }

    pub fn reclaim_array(&mut self, address: usize) -> bool {
        unsafe {
            let mut page: *mut _Page = self;
            while !page.is_null() {
                if (*page).deallocate_exclusive_page(address as *mut _Page) {
                    return true;
                }
                page = *(*page).get_extension_page_location();
            }
        }

        // If we arrive here, we have a memory leak.
        false
    }

    pub fn get_page(address: *mut u8) -> *mut _Page {
        unsafe { &mut *((address as usize & !_PAGE_SIZE - 1) as *mut _Page) }
    }

    fn deallocate_exclusive_page(&mut self, page: *mut _Page) -> bool {
        unsafe {
            // Find the extension Page pointer
            let mut extension_pointer = self.get_extension_page_location().offset(-1);
            let next_extension_page_location = self.get_next_exclusive_page_location();
            while extension_pointer > next_extension_page_location {
                if *extension_pointer == page {
                    break;
                }
                extension_pointer = extension_pointer.offset(-1);
            }

            // Report if we could not find it
            if extension_pointer == next_extension_page_location {
                return false;
            }

            // Shift the remaining array one position up
            while extension_pointer > next_extension_page_location {
                let pp_page = extension_pointer;
                *pp_page = *(pp_page.offset(-1));
                extension_pointer = extension_pointer.offset(-1);
            }
        }

        // Make room for one more extension
        self.exclusive_pages -= 1;
        unsafe {
            (*page).forget();
        }

        true
    }
}

#[test]
fn test_page() {
    unsafe {
        // Allocate a page
        let memory = alloc(Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE));
        assert_ne!(memory, null_mut());

        // Write some numbers to the page memory
        for i in 0.._PAGE_SIZE {
            let ptr = memory.offset(i as isize);
            *ptr = i as u8
        }

        // Initialize a _Page object at the page start
        let page = &mut *(memory as *mut _Page);

        assert_ne!(page.next_object_offset, 0);
        assert_ne!(page.exclusive_pages, 0);

        page.reset();

        assert_eq!(page.next_object_offset, size_of::<_Page>() as i32);
        assert_eq!(page.exclusive_pages, 0);
        assert_eq!(page.is_oversized(), false);
        assert_eq!(page as *mut _Page, page.current_page);

        {
            let extension_page_location = page.get_extension_page_location();
            assert_eq!(
                extension_page_location as usize,
                page as *const _Page as usize + _PAGE_SIZE - size_of::<*mut *mut _Page>()
            );
        }

        {
            let mut location = page.get_next_location();
            assert_eq!(
                location as usize,
                page as *const _Page as usize + size_of::<_Page>()
            );

            let mut memory = page.allocate_raw(1, 1);
            location += 1;
            assert_eq!(page.get_next_location(), location);
            *memory = 42;
            memory = page.allocate_raw(1, 2);
            location += 2;
            assert_eq!(page.get_next_location(), location);
            *memory = 43;
        }
    }
}
<commit_msg>Some testing<commit_after>use std::alloc::alloc;
use std::alloc::dealloc;
use std::alloc::Layout;
use std::mem::size_of;
use std::ptr::null_mut;

const _PAGE_SIZE: usize = 0x1000;

pub struct _Page {
    current_page: *mut _Page,
    next_object_offset: i32,
    exclusive_pages: i32,
}

impl _Page {
    pub fn reset(&mut self) {
        unsafe {
            *(self.get_extension_page_location()) = null_mut();
        }
        self.next_object_offset = size_of::<_Page>() as i32;
        self.exclusive_pages = 0;
        self.current_page = &mut *self;
    }

    pub fn clear(&mut self) {
        self.deallocate_extensions();
        self.reset();
    }

    pub fn is_oversized(&self) -> bool {
        self.current_page.is_null()
    }

    fn get_extension_page_location(&self) -> *mut *mut _Page {
        // Convert self to page location
        let self_location = self as *const _Page as usize;

        // Advance one page size so we are past the end of our page
        let location_behind_page = (self_location + _PAGE_SIZE) as *mut *mut _Page;

        // Go back one pointer size
        unsafe { location_behind_page.offset(-1) }
    }

    fn get_next_location(&self) -> usize {
        self as *const _Page as usize + self.next_object_offset as usize
    }

    fn set_next_location(&mut self, location: usize) {
        let self_location = self as *const _Page as usize;
        self.next_object_offset = (location - self_location as usize) as i32;
    }

    fn get_next_exclusive_page_location(&self) -> *mut *mut _Page {
        unsafe {
            self.get_extension_page_location()
                .offset(-(self.exclusive_pages as isize + 1))
        }
    }

    pub fn allocate_raw(&mut self, size: usize, align: usize) -> *mut u8 {
        if self as *mut _Page != self.current_page {
            unsafe {
                // We're already known to be full, so we delegate to the current page
                let new_object = (*self.current_page).allocate_raw(size, align);

                // Possibly our current page was also full so we propagate back the new current page
                let allocating_page = _Page::get_page(new_object);
                if allocating_page != self.current_page && (!(*allocating_page).is_oversized()) {
                    self.current_page = allocating_page;
                }
                return new_object;
            }
        }

        // Try to allocate from ourselves
        let location = self.get_next_location();
        let aligned_location = (location + align - 1) & !(align - 1);
        let next_location = aligned_location + size;
        if next_location <= self.get_next_exclusive_page_location() as usize {
            self.set_next_location(next_location);
            return location as *mut u8;
        }

        // So the space did not fit.

        // Calculate gross size to decide whether we're oversized
        if size_of::<_Page>() + size + size_of::<*mut *mut _Page>() > _PAGE_SIZE {
            if self.get_next_location() >= self.get_next_exclusive_page_location() as usize {
                // Allocate an extension page and try again with it
                unsafe {
                    return (*self.allocate_extension_page()).allocate_raw(size, align);
                }
            }

            unsafe {
                // We allocate oversized objects directly.
                let memory = alloc(Layout::from_size_align_unchecked(
                    size + size_of::<_Page>(),
                    _PAGE_SIZE,
                ));

                // Initialize a _Page object at the page start
                let page = memory as *mut _Page;

                // Oversized pages have no current_page
                (*page).current_page = null_mut();

                // Set the size since we will need it when deallocating
                (*page).next_object_offset = (size % 0x100000000) as i32;
                (*page).exclusive_pages = (size / 0x100000000) as i32;

                *(self.get_next_exclusive_page_location()) = page;
                self.exclusive_pages += 1;
                return page.offset(1) as *mut u8;
            }
        }

        // So we're not oversized. Create extension page and let it allocate.
        unsafe { (*self.allocate_extension_page()).allocate_raw(size, align) }
    }

    fn allocate_extension_page(&mut self) -> *mut _Page {
        unsafe {
            let page = _Page::allocate_page();
            *(self.get_extension_page_location()) = page;
            self.current_page = page;
            &mut *page
        }
    }

    fn allocate_page() -> *mut _Page {
        unsafe {
            let page =
                alloc(Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE)) as *mut _Page;
            (*page).reset();
            page
        }
    }

    pub fn allocate_exclusive_page(&mut self) -> *mut _Page {
        unsafe {
            if self as *mut _Page != self.current_page {
                // We're already known to be full, so we delegate to the current page
                return (*self.current_page).allocate_exclusive_page();
            }

            // Check first whether we need an ordinary extension
            if self.get_next_location() as usize >= self.get_next_exclusive_page_location() as usize
            {
                // Allocate an extension page with default size
                return (*self.allocate_extension_page()).allocate_exclusive_page();
            }

            let page = _Page::allocate_page();
            *(self.get_next_exclusive_page_location()) = page;
            self.exclusive_pages += 1;
            &mut *page
        }
    }

    pub fn extend(&mut self, top: usize, size: usize) -> bool {
        if top != self.get_next_location() {
            return false;
        }

        let new_top = top + size;
        if new_top > self.get_next_exclusive_page_location() as usize {
            return false;
        }
        self.set_next_location(new_top);

        true
    }

    fn deallocate_extensions(&mut self) {
        let mut page: *mut _Page = self;
        unsafe {
            while !page.is_null() {
                let extension_pointer = (*page).get_extension_page_location();
                for i in 1..(*page).exclusive_pages {
                    let mut exclusive_page = &mut **(extension_pointer.offset(-(i as isize)));
                    if !exclusive_page.is_oversized() {
                        exclusive_page.deallocate_extensions();
                    }
                    exclusive_page.forget();
                }

                if page != self as *mut _Page {
                    (*page).forget();
                }

                page = *extension_pointer;
            }
        }
    }

    pub fn forget(&self) {
        let size = if self.current_page == null_mut() {
            self.next_object_offset as usize + self.exclusive_pages as usize * 0x100000000
        } else {
            _PAGE_SIZE
        };
        unsafe {
            dealloc(
                self as *const _Page as *mut u8,
                Layout::from_size_align_unchecked(size, _PAGE_SIZE),
            )
        }
    }

    pub fn reclaim_array(&mut self, address: usize) -> bool {
        unsafe {
            let mut page: *mut _Page = self;
            while !page.is_null() {
                if (*page).deallocate_exclusive_page(address as *mut _Page) {
                    return true;
                }
                page = *(*page).get_extension_page_location();
            }
        }

        // If we arrive here, we have a memory leak.
        false
    }

    pub fn get_page(address: *mut u8) -> *mut _Page {
        unsafe { &mut *((address as usize & !_PAGE_SIZE - 1) as *mut _Page) }
    }

    fn deallocate_exclusive_page(&mut self, page: *mut _Page) -> bool {
        unsafe {
            // Find the extension Page pointer
            let mut extension_pointer = self.get_extension_page_location().offset(-1);
            let next_extension_page_location = self.get_next_exclusive_page_location();
            while extension_pointer > next_extension_page_location {
                if *extension_pointer == page {
                    break;
                }
                extension_pointer = extension_pointer.offset(-1);
            }

            // Report if we could not find it
            if extension_pointer == next_extension_page_location {
                return false;
            }

            // Shift the remaining array one position up
            while extension_pointer > next_extension_page_location {
                let pp_page = extension_pointer;
                *pp_page = *(pp_page.offset(-1));
                extension_pointer = extension_pointer.offset(-1);
            }
        }

        // Make room for one more extension
        self.exclusive_pages -= 1;
        unsafe {
            (*page).forget();
        }

        true
    }
}

#[test]
fn test_page() {
    unsafe {
        // Allocate a page
        let memory = alloc(Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE));
        assert_ne!(memory, null_mut());

        // Write some numbers to the page memory
        for i in 0.._PAGE_SIZE {
            let ptr = memory.offset(i as isize);
            *ptr = i as u8
        }

        // Initialize a _Page object at the page start
        let page = &mut *(memory as *mut _Page);

        assert_ne!(page.next_object_offset, 0);
        assert_ne!(page.exclusive_pages, 0);

        page.reset();

        assert_eq!(page.next_object_offset, size_of::<_Page>() as i32);
        assert_eq!(page.exclusive_pages, 0);
        assert_eq!(page.is_oversized(), false);
        assert_eq!(page as *mut _Page, page.current_page);

        {
            let extension_page_location = page.get_extension_page_location();
            assert_eq!(
                extension_page_location as usize,
                page as *const _Page as usize + _PAGE_SIZE - size_of::<*mut *mut _Page>()
            );
        }

        {
            let mut location = page.get_next_location();
            assert_eq!(
                location as usize,
                page as *const _Page as usize + size_of::<_Page>()
            );

            let answer = page.allocate_raw(1, 1);
            location += 1;
            assert_eq!(page.get_next_location(), location);
            *answer = 42;

            let another = page.allocate_raw(1, 2);
            location += 2;
            assert_eq!(page.get_next_location(), location);
            *another = 43;

            let eau = page.allocate_raw(4, 4) as *mut i32;
            location += 5;
            assert_eq!(page.get_next_location(), location);
            *eau = 4711;

            // Allocate an oversized page which should cause allocating an exclusive page
            let array = page.allocate_raw(_PAGE_SIZE, 8) as *mut usize;
            for i in 0.._PAGE_SIZE / size_of::<usize>() - 1 {
                *(array.offset(i as isize)) = i;
            }
            assert_eq!(page.get_next_location(), location);
            assert_eq!(page as *mut _Page, page.current_page);

            // Overflow the page
            for _ in 0.._PAGE_SIZE {
                page.allocate_raw(1, 1);
            }
            assert_ne!(page as *mut _Page, page.current_page);
            assert_eq!(*(page.get_extension_page_location()), page.current_page);
            assert_eq!((*page.current_page).exclusive_pages, 0);
            assert_eq!((*page.current_page).current_page, page.current_page);

            assert_eq!(page.exclusive_pages, 1);
            assert_eq!(*answer, 42);
            assert_eq!(*another, 43);
            assert_eq!(*eau, 4711);

            let exclusive_page = page.get_next_exclusive_page_location().offset(1);
            assert_eq!((**exclusive_page).current_page, null_mut());

            page.clear();
            assert_eq!(page.exclusive_pages, 0);
            page.forget();
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use super::{Array, Dimension};

/// HACK: fmt::rt::FlagAlternate has been hidden away
const FLAG_ALTERNATE: usize = 2;

fn format_array<A, D: Dimension, F>(view: &Array<A, D>, f: &mut fmt::Formatter,
                                    mut format: F) -> fmt::Result where
    F: FnMut(&mut fmt::Formatter, &A) -> fmt::Result,
{
    let ndim = view.dim.slice().len();
    /* private nowadays
    if ndim > 0 && f.width.is_none() {
        f.width = Some(4)
    }
    */
    // None will be an empty iter.
    let mut last_index = match view.dim.first_index() {
        None => view.dim.clone(),
        Some(ix) => ix,
    };
    for _ in 0..ndim {
        try!(write!(f, "["));
    }
    let mut first = true;
    // Simply use the indexed iterator, and take the index wraparounds
    // as cues for when to add []'s and how many to add.
    for (index, elt) in view.indexed_iter() {
        let take_n = if ndim == 0 { 1 } else { ndim - 1 };
        let mut update_index = false;
        for (i, (a, b)) in index.slice().iter().take(take_n)
                        .zip(last_index.slice().iter())
                        .enumerate()
        {
            if a != b {
                // New row.
                // # of ['s needed
                let n = ndim - i - 1;
                for _ in 0..n {
                    try!(write!(f, "]"));
                }
                try!(write!(f, ","));
                if f.flags() & (1 << FLAG_ALTERNATE) == 0 {
                    try!(write!(f, "\n"));
                }
                for _ in 0..ndim - n {
                    try!(write!(f, " "));
                }
                for _ in 0..n {
                    try!(write!(f, "["));
                }
                first = true;
                update_index = true;
                break;
            }
        }
        if !first {
            try!(write!(f, ", "));
        }
        first = false;
        try!(format(f, elt));

        if update_index {
            last_index = index;
        }
    }
    for _ in 0..ndim {
        try!(write!(f, "]"));
    }
    Ok(())
}

// NOTE: We can impl other fmt traits here
impl<'a, A: fmt::Display, D: Dimension> fmt::Display for Array<A, D>
{
    /// Format the array using `Display` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

impl<'a, A: fmt::Debug, D: Dimension> fmt::Debug for Array<A, D>
{
    /// Format the array using `Debug` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

impl<'a, A: fmt::LowerExp, D: Dimension> fmt::LowerExp for Array<A, D>
{
    /// Format the array using `LowerExp` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#e}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

impl<'a, A: fmt::UpperExp, D: Dimension> fmt::UpperExp for Array<A, D>
{
    /// Format the array using `UpperExp` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#E}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

<commit_msg>Use Formatter::alternate<commit_after>use std::fmt;
use super::{Array, Dimension};

fn format_array<A, D: Dimension, F>(view: &Array<A, D>, f: &mut fmt::Formatter,
                                    mut format: F) -> fmt::Result where
    F: FnMut(&mut fmt::Formatter, &A) -> fmt::Result,
{
    let ndim = view.dim.slice().len();
    /* private nowadays
    if ndim > 0 && f.width.is_none() {
        f.width = Some(4)
    }
    */
    // None will be an empty iter.
    let mut last_index = match view.dim.first_index() {
        None => view.dim.clone(),
        Some(ix) => ix,
    };
    for _ in 0..ndim {
        try!(write!(f, "["));
    }
    let mut first = true;
    // Simply use the indexed iterator, and take the index wraparounds
    // as cues for when to add []'s and how many to add.
    for (index, elt) in view.indexed_iter() {
        let take_n = if ndim == 0 { 1 } else { ndim - 1 };
        let mut update_index = false;
        for (i, (a, b)) in index.slice().iter().take(take_n)
                        .zip(last_index.slice().iter())
                        .enumerate()
        {
            if a != b {
                // New row.
                // # of ['s needed
                let n = ndim - i - 1;
                for _ in 0..n {
                    try!(write!(f, "]"));
                }
                try!(write!(f, ","));
                if !f.alternate() {
                    try!(write!(f, "\n"));
                }
                for _ in 0..ndim - n {
                    try!(write!(f, " "));
                }
                for _ in 0..n {
                    try!(write!(f, "["));
                }
                first = true;
                update_index = true;
                break;
            }
        }
        if !first {
            try!(write!(f, ", "));
        }
        first = false;
        try!(format(f, elt));

        if update_index {
            last_index = index;
        }
    }
    for _ in 0..ndim {
        try!(write!(f, "]"));
    }
    Ok(())
}

// NOTE: We can impl other fmt traits here
impl<'a, A: fmt::Display, D: Dimension> fmt::Display for Array<A, D>
{
    /// Format the array using `Display` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

impl<'a, A: fmt::Debug, D: Dimension> fmt::Debug for Array<A, D>
{
    /// Format the array using `Debug` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

impl<'a, A: fmt::LowerExp, D: Dimension> fmt::LowerExp for Array<A, D>
{
    /// Format the array using `LowerExp` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#e}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

impl<'a, A: fmt::UpperExp, D: Dimension> fmt::UpperExp for Array<A, D>
{
    /// Format the array using `UpperExp` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#E}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

<|endoftext|>


<commit_before>use futures::channel::oneshot;
use futures::executor::{block_on, block_on_stream};
use futures::future::{self, join, Future, FutureExt, TryFutureExt};
use futures::stream::{StreamExt, FuturesOrdered};
use futures_test::task::noop_context;
use std::any::Any;

#[test]
fn works_1() {
    let (a_tx, a_rx) = oneshot::channel::<i32>();
    let (b_tx, b_rx) = oneshot::channel::<i32>();
    let (c_tx, c_rx) = oneshot::channel::<i32>();

    let mut stream = vec![a_rx, b_rx, c_rx].into_iter().collect::<FuturesOrdered<_>>();

    b_tx.send(99).unwrap();
    assert!(stream.poll_next_unpin(&mut noop_context()).is_pending());

    a_tx.send(33).unwrap();
    c_tx.send(33).unwrap();

    let mut iter = block_on_stream(stream);
    assert_eq!(Some(Ok(33)), iter.next());
    assert_eq!(Some(Ok(99)), iter.next());
    assert_eq!(Some(Ok(33)), iter.next());
    assert_eq!(None, iter.next());
}

#[test]
fn works_2() {
    let (a_tx, a_rx) = oneshot::channel::<i32>();
    let (b_tx, b_rx) = oneshot::channel::<i32>();
    let (c_tx, c_rx) = oneshot::channel::<i32>();

    let mut stream = vec![
        a_rx.boxed(),
        join(b_rx, c_rx).map(|(a, b)| Ok(a? + b?)).boxed(),
    ].into_iter().collect::<FuturesOrdered<_>>();

    let mut cx = noop_context();
    a_tx.send(33).unwrap();
    b_tx.send(33).unwrap();
    assert!(stream.poll_next_unpin(&mut cx).is_ready());
    assert!(stream.poll_next_unpin(&mut cx).is_pending());
    c_tx.send(33).unwrap();
    assert!(stream.poll_next_unpin(&mut cx).is_ready());
}

#[test]
fn from_iterator() {
    let stream = vec![
        future::ready::<i32>(1),
        future::ready::<i32>(2),
        future::ready::<i32>(3)
    ].into_iter().collect::<FuturesOrdered<_>>();
    assert_eq!(stream.len(), 3);
    assert_eq!(block_on(stream.collect::<Vec<_>>()), vec![1,2,3]);
}

#[test]
fn queue_never_unblocked() {
    let (_a_tx, a_rx) = oneshot::channel::<Box<dyn Any + Send>>();
    let (b_tx, b_rx) = oneshot::channel::<Box<dyn Any + Send>>();
    let (c_tx, c_rx) = oneshot::channel::<Box<dyn Any + Send>>();

    let mut stream = vec![
        Box::new(a_rx) as Box<dyn Future<Output = _> + Unpin>,
        Box::new(future::try_select(b_rx, c_rx)
            .map_err(|e| e.factor_first().0)
            .and_then(|e| future::ok(Box::new(e) as Box<dyn Any + Send>))) as _,
    ].into_iter().collect::<FuturesOrdered<_>>();

    let cx = &mut noop_context();
    for _ in 0..10 {
        assert!(stream.poll_next_unpin(cx).is_pending());
    }

    b_tx.send(Box::new(())).unwrap();
    assert!(stream.poll_next_unpin(cx).is_pending());
    c_tx.send(Box::new(())).unwrap();
    assert!(stream.poll_next_unpin(cx).is_pending());
    assert!(stream.poll_next_unpin(cx).is_pending());
}
<commit_msg>futures: tests/futures_ordered.rs : Guard against failures w/o features<commit_after>#[cfg(all(feature = "alloc", feature="executor"))]
#[test]
fn works_1() {
    use futures::channel::oneshot;
    use futures::executor::block_on_stream;
    use futures::stream::{StreamExt, FuturesOrdered};
    use futures_test::task::noop_context;

    let (a_tx, a_rx) = oneshot::channel::<i32>();
    let (b_tx, b_rx) = oneshot::channel::<i32>();
    let (c_tx, c_rx) = oneshot::channel::<i32>();

    let mut stream = vec![a_rx, b_rx, c_rx].into_iter().collect::<FuturesOrdered<_>>();

    b_tx.send(99).unwrap();
    assert!(stream.poll_next_unpin(&mut noop_context()).is_pending());

    a_tx.send(33).unwrap();
    c_tx.send(33).unwrap();

    let mut iter = block_on_stream(stream);
    assert_eq!(Some(Ok(33)), iter.next());
    assert_eq!(Some(Ok(99)), iter.next());
    assert_eq!(Some(Ok(33)), iter.next());
    assert_eq!(None, iter.next());
}

#[cfg(feature = "alloc")]
#[test]
fn works_2() {
    use futures::channel::oneshot;
    use futures::future::{join, FutureExt};
    use futures::stream::{StreamExt, FuturesOrdered};
    use futures_test::task::noop_context;

    let (a_tx, a_rx) = oneshot::channel::<i32>();
    let (b_tx, b_rx) = oneshot::channel::<i32>();
    let (c_tx, c_rx) = oneshot::channel::<i32>();

    let mut stream = vec![
        a_rx.boxed(),
        join(b_rx, c_rx).map(|(a, b)| Ok(a? + b?)).boxed(),
    ].into_iter().collect::<FuturesOrdered<_>>();

    let mut cx = noop_context();
    a_tx.send(33).unwrap();
    b_tx.send(33).unwrap();
    assert!(stream.poll_next_unpin(&mut cx).is_ready());
    assert!(stream.poll_next_unpin(&mut cx).is_pending());
    c_tx.send(33).unwrap();
    assert!(stream.poll_next_unpin(&mut cx).is_ready());
}

#[cfg(feature = "executor")]
#[test]
fn from_iterator() {
    use futures::executor::block_on;
    use futures::future;
    use futures::stream::{StreamExt, FuturesOrdered};

    let stream = vec![
        future::ready::<i32>(1),
        future::ready::<i32>(2),
        future::ready::<i32>(3)
    ].into_iter().collect::<FuturesOrdered<_>>();
    assert_eq!(stream.len(), 3);
    assert_eq!(block_on(stream.collect::<Vec<_>>()), vec![1,2,3]);
}

#[cfg(feature = "alloc")]
#[test]
fn queue_never_unblocked() {
    use futures::channel::oneshot;
    use futures::future::{self, Future, TryFutureExt};
    use futures::stream::{StreamExt, FuturesOrdered};
    use futures_test::task::noop_context;
    use std::any::Any;

    let (_a_tx, a_rx) = oneshot::channel::<Box<dyn Any + Send>>();
    let (b_tx, b_rx) = oneshot::channel::<Box<dyn Any + Send>>();
    let (c_tx, c_rx) = oneshot::channel::<Box<dyn Any + Send>>();

    let mut stream = vec![
        Box::new(a_rx) as Box<dyn Future<Output = _> + Unpin>,
        Box::new(future::try_select(b_rx, c_rx)
            .map_err(|e| e.factor_first().0)
            .and_then(|e| future::ok(Box::new(e) as Box<dyn Any + Send>))) as _,
    ].into_iter().collect::<FuturesOrdered<_>>();

    let cx = &mut noop_context();
    for _ in 0..10 {
        assert!(stream.poll_next_unpin(cx).is_pending());
    }

    b_tx.send(Box::new(())).unwrap();
    assert!(stream.poll_next_unpin(cx).is_pending());
    c_tx.send(Box::new(())).unwrap();
    assert!(stream.poll_next_unpin(cx).is_pending());
    assert!(stream.poll_next_unpin(cx).is_pending());
}
<|endoftext|>


<commit_before>use ber;
use ber::error::ASN1Error as Error;

use std::io::Write;

use byteorder::BigEndian;
use byteorder::WriteBytesExt;

use ber::common::{self, Tag};

pub fn write(tag: common::Tag, mut w: &mut Write) -> ber::Result<()>
{
    try!(write_type(tag._type, w));
    try!(write_length(tag._length, w));
    try!(write_value(tag._value, w));

    Ok(())
}

fn write_type(tagtype: common::Type, mut w: &mut Write) -> ber::Result<()>
{
    let class_number = match tagtype.class
    {
        common::Class::Universal(_) => common::ClassNumber::Universal,
        common::Class::Application(_) => common::ClassNumber::Application,
        common::Class::ContextSpecific(_) => common::ClassNumber::ContextSpecific,
        common::Class::Private(_) => common::ClassNumber::Private,
    };

    let mut extended_tag: Option<Vec<u8>> = None;

    let type_byte =
            // First two bits: Class
            (class_number as u8) << 6 |
            // Bit 6: Primitive/Constructed
            (tagtype.structure as u8) << 5 |
            // Bit 5-1: Tag Number
            match tagtype.class
            {
                // tag will never be bigger than 30 so this is ok
                common::Class::Universal(tag) => (tag as u8),
                common::Class::Application(tag) |
                common::Class::ContextSpecific(tag) |
                common::Class::Private(tag) =>
                {
                    if tag > 30
                    {
                        let mut tagbytes: Vec<u8> = Vec::new();

                        let mut tag = tag;
                        while tag > 0
                        {
                            let mut byte = (tag & 0x7F) as u8;

                            tag >>= 7;

                            tagbytes.push(byte);
                        }

                        extended_tag = Some(tagbytes);

                        // This means we need to set the 5 tag bits to 11111, so 31 or 0x1F
                        31
                    }
                    else
                    {
                        extended_tag = None;
                        (tag as u8)
                    }
                },
            }; // let type_byte

    try!(w.write_u8(type_byte));

    let mut written = 1;

    if let Some(mut ext_bytes) = extended_tag
    {
        for _ in 0..ext_bytes.len()-1
        {
            let mut byte = ext_bytes.pop().unwrap();

            // Set the first bit
            byte |= 0x80;

            w.write_u8(byte);
        }

        let byte = ext_bytes.pop().unwrap();
        w.write_u8(byte);
    }

    Ok(())
}

// Yes I know you could overflow the length in theory. But, do you have 2^64 bytes of memory?
fn write_length(mut length: u64, mut w: &mut Write) -> ber::Result<()>
{
    // Short form
    if length < 128
    {
        try!(w.write_u8(length as u8));

        Ok(())
    }
    // Long form
    else
    {
        let mut count = 0u8;
        let mut len = length;
        while {count += 1; len >>= 8; len > 0 }{}

        try!(w.write_u8(count | 0x80));
        w.write_uint::<BigEndian>(length, count as usize);

        Ok(())
    }
}

fn write_value(payload: common::Payload, mut w: &mut Write) -> ber::Result<()>
{
    match payload
    {
        common::Payload::Primitive(ref value) =>
        {
            try!(w.write_all(value));
            Ok(())
        },
        common::Payload::Constructed(tags) =>
        {
            for tag in tags
            {
                try!(write(tag, w));
            }
            Ok(())
        }
    }
}

#[cfg(test)]
mod test
{
    use super::*;
    use ber::common;
    use std::io::Cursor;

    use byteorder::WriteBytesExt;
    use byteorder::BigEndian;

    #[test]
    fn encode_simple_tag()
    {
        let mut payload: Vec<u8> = Vec::new();
        payload.write_i16::<BigEndian>(1616);

        let tagtype = common::Type {
            class: common::Class::Universal(common::UniversalTypes::Integer),
            structure: common::Structure::Primitive
        };
        let pl = common::Payload::Primitive(payload);

        let tag = common::construct(tagtype, pl);

        let mut buf = Vec::<u8>::new();
        super::write(tag, &mut buf).unwrap();

        println!("{:?}", buf);

        assert!(buf == vec![0x2, 0x2, 0x06, 0x50]);
    }

    #[test]
    fn encode_constructed_tag()
    {
        let child =
        {
            let class = common::Class::ContextSpecific(0);
            let pl = common::Payload::Primitive("Hello World!".to_string().into_bytes());

            common::construct(class, pl)
        };

        println!("{:?}", child);

        let parent =
        {
            let class = common::Class::Universal(common::UniversalTypes::Sequence);
            let pl = common::Payload::Constructed(vec![child]);

            common::construct(class, pl)
        };

        println!("{:?}", parent);

        let mut buf = Vec::<u8>::new();
        super::write(parent, &mut buf);

        println!("{:?}", buf);

        assert!(buf == vec![48, 14, 128, 12, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
    }

    #[test]
    fn encode_extended_type_tags()
    {

        let tag = {
            let class = common::Class::ContextSpecific(1000);
            let pl = common::Payload::Primitive("second".to_string().into_bytes());

            common::construct(class, pl)
        };

        let mut buf = Vec::<u8>::new();
        super::write(tag, &mut buf);

        println!("{:?}", buf);

        assert!(buf == vec![0x9F,0x87,0x68,0x06,0x73,0x65,0x63,0x6F,0x6E,0x64]);
    }

    #[test]
    fn encode_long_length_tags()
    {
        let name =
        {
            let class = common::Class::ContextSpecific(0);
            let pl = common::Payload::Primitive("JustALongTag".to_string().into_bytes());

            common::construct(class, pl)
        };

        let value =
        {
            let class = common::Class::ContextSpecific(1);
            let pl = common::Payload::Primitive("JustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTag".to_string().into_bytes());

            common::construct(class, pl)
        };

        let seq =
        {
            let class = common::Class::Universal(common::UniversalTypes::Sequence);
            let pl = common::Payload::Constructed(vec![name, value]);

            common::construct(class, pl)
        };

        let mut buf = Vec::<u8>::new();
        super::write(seq, &mut buf);

        println!("{:?}", buf);
        assert!(buf == vec![
            0x30, 0x82, 0x01, 0x01,
            0x80, 0x0C, 0x4A, 0x75,
            0x73, 0x74, 0x41, 0x4C,
            0x6F, 0x6E, 0x67, 0x54,
            0x61, 0x67, 0x81, 0x81,
            0xF0, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67,
        ]);
    }
}
<commit_msg>Switch to Encoder-struct based encoding<commit_after>use ber;
use ber::error::ASN1Error as Error;

use std::io;
use std::io::Write;

use byteorder::BigEndian;
use byteorder::WriteBytesExt;

use ber::common::{self, Tag};

pub struct Encoder<W>
{
    buf: W,
}

impl<W: io::Write> Encoder<W>
{
    pub fn from_writer(wtr: W) -> Encoder<io::BufWriter<W>>
    {
        Encoder::from_writer_raw(io::BufWriter::new(wtr))
    }

    pub fn from_writer_raw(wtr: W) -> Encoder<W>
    {
        Encoder
        {
            buf: wtr,
        }
    }

    pub fn flush(&mut self) -> ber::Result<()>
    {
        try!(self.buf.flush());

        Ok(())
    }

    pub fn encode(&mut self, tag: common::Tag) -> ber::Result<()>
    {
        try!(write_type(tag._type, &mut self.buf));
        try!(write_length(tag._length, &mut self.buf));
        try!(write_value(tag._value, &mut self.buf));

        Ok(())
    }
}

fn write(tag: common::Tag, mut w: &mut Write) -> ber::Result<()>
{
    try!(write_type(tag._type, w));
    try!(write_length(tag._length, w));
    try!(write_value(tag._value, w));

    Ok(())
}

fn write_type(tagtype: common::Type, mut w: &mut Write) -> ber::Result<()>
{
    let class_number = match tagtype.class
    {
        common::Class::Universal(_) => common::ClassNumber::Universal,
        common::Class::Application(_) => common::ClassNumber::Application,
        common::Class::ContextSpecific(_) => common::ClassNumber::ContextSpecific,
        common::Class::Private(_) => common::ClassNumber::Private,
    };

    let mut extended_tag: Option<Vec<u8>> = None;

    let type_byte =
            // First two bits: Class
            (class_number as u8) << 6 |
            // Bit 6: Primitive/Constructed
            (tagtype.structure as u8) << 5 |
            // Bit 5-1: Tag Number
            match tagtype.class
            {
                // tag will never be bigger than 30 so this is ok
                common::Class::Universal(tag) => (tag as u8),
                common::Class::Application(tag) |
                common::Class::ContextSpecific(tag) |
                common::Class::Private(tag) =>
                {
                    if tag > 30
                    {
                        let mut tagbytes: Vec<u8> = Vec::new();

                        let mut tag = tag;
                        while tag > 0
                        {
                            let mut byte = (tag & 0x7F) as u8;

                            tag >>= 7;

                            tagbytes.push(byte);
                        }

                        extended_tag = Some(tagbytes);

                        // This means we need to set the 5 tag bits to 11111, so 31 or 0x1F
                        31
                    }
                    else
                    {
                        extended_tag = None;
                        (tag as u8)
                    }
                },
            }; // let type_byte

    try!(w.write_u8(type_byte));

    let mut written = 1;

    if let Some(mut ext_bytes) = extended_tag
    {
        for _ in 0..ext_bytes.len()-1
        {
            let mut byte = ext_bytes.pop().unwrap();

            // Set the first bit
            byte |= 0x80;

            w.write_u8(byte);
        }

        let byte = ext_bytes.pop().unwrap();
        w.write_u8(byte);
    }

    Ok(())
}

// Yes I know you could overflow the length in theory. But, do you have 2^64 bytes of memory?
fn write_length(mut length: u64, mut w: &mut Write) -> ber::Result<()>
{
    // Short form
    if length < 128
    {
        try!(w.write_u8(length as u8));

        Ok(())
    }
    // Long form
    else
    {
        let mut count = 0u8;
        let mut len = length;
        while {count += 1; len >>= 8; len > 0 }{}

        try!(w.write_u8(count | 0x80));
        w.write_uint::<BigEndian>(length, count as usize);

        Ok(())
    }
}

fn write_value(payload: common::Payload, mut w: &mut Write) -> ber::Result<()>
{
    match payload
    {
        common::Payload::Primitive(ref value) =>
        {
            try!(w.write_all(value));
            Ok(())
        },
        common::Payload::Constructed(tags) =>
        {
            for tag in tags
            {
                try!(write(tag, w));
            }
            Ok(())
        }
    }
}

#[cfg(test)]
mod test
{
    use super::*;
    use ber::common;
    use std::io::Cursor;

    use byteorder::WriteBytesExt;
    use byteorder::BigEndian;

    #[test]
    fn encode_simple_tag()
    {
        let mut payload: Vec<u8> = Vec::new();
        payload.write_i16::<BigEndian>(1616);

        let tagtype = common::Type {
            class: common::Class::Universal(common::UniversalTypes::Integer),
            structure: common::Structure::Primitive
        };
        let pl = common::Payload::Primitive(payload);

        let tag = common::construct(tagtype, pl);

        let mut buf = Vec::<u8>::new();
        super::write(tag, &mut buf).unwrap();

        println!("{:?}", buf);

        assert!(buf == vec![0x2, 0x2, 0x06, 0x50]);
    }

    #[test]
    fn encode_constructed_tag()
    {
        let child =
        {
            let class = common::Class::ContextSpecific(0);
            let pl = common::Payload::Primitive("Hello World!".to_string().into_bytes());

            common::construct(class, pl)
        };

        println!("{:?}", child);

        let parent =
        {
            let class = common::Class::Universal(common::UniversalTypes::Sequence);
            let pl = common::Payload::Constructed(vec![child]);

            common::construct(class, pl)
        };

        println!("{:?}", parent);

        let mut buf = Vec::<u8>::new();
        super::write(parent, &mut buf);

        println!("{:?}", buf);

        assert!(buf == vec![48, 14, 128, 12, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
    }

    #[test]
    fn encode_extended_type_tags()
    {

        let tag = {
            let class = common::Class::ContextSpecific(1000);
            let pl = common::Payload::Primitive("second".to_string().into_bytes());

            common::construct(class, pl)
        };

        let mut buf = Vec::<u8>::new();
        super::write(tag, &mut buf);

        println!("{:?}", buf);

        assert!(buf == vec![0x9F,0x87,0x68,0x06,0x73,0x65,0x63,0x6F,0x6E,0x64]);
    }

    #[test]
    fn encode_long_length_tags()
    {
        let name =
        {
            let class = common::Class::ContextSpecific(0);
            let pl = common::Payload::Primitive("JustALongTag".to_string().into_bytes());

            common::construct(class, pl)
        };

        let value =
        {
            let class = common::Class::ContextSpecific(1);
            let pl = common::Payload::Primitive("JustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTagJustALongTag".to_string().into_bytes());

            common::construct(class, pl)
        };

        let seq =
        {
            let class = common::Class::Universal(common::UniversalTypes::Sequence);
            let pl = common::Payload::Constructed(vec![name, value]);

            common::construct(class, pl)
        };

        let mut buf = Vec::<u8>::new();
        super::write(seq, &mut buf);

        println!("{:?}", buf);
        assert!(buf == vec![
            0x30, 0x82, 0x01, 0x01,
            0x80, 0x0C, 0x4A, 0x75,
            0x73, 0x74, 0x41, 0x4C,
            0x6F, 0x6E, 0x67, 0x54,
            0x61, 0x67, 0x81, 0x81,
            0xF0, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67, 0x4A, 0x75, 0x73,
            0x74, 0x41, 0x4C, 0x6F,
            0x6E, 0x67, 0x54, 0x61,
            0x67,
        ]);
    }
}
<|endoftext|>


<commit_before>extern crate nom;
extern crate num;

use std::mem;
use std::fmt;

use nom::{IResult, ErrorKind};
use num::bigint;
use num::bigint::ToBigInt;
use num::traits::{Zero, One};

static BERT_MAGIC_NUMBER: u8 = 131;
static SMALL_INTEGER_EXT: u8 = 97;
static INTEGER_EXT: u8 = 98;
static FLOAT_EXT: u8 = 99;
static ATOM_EXT: u8 = 100;
static SMALL_TUPLE_EXT: u8 = 104;
static LARGE_TUPLE_EXT: u8 = 105;
static NIL_EXT: u8 = 106;
static STRING_EXT: u8 = 107;
static LIST_EXT: u8 = 108;
static BINARY_EXT: u8 = 109;
static SMALL_BIG_EXT: u8 = 110;
static LARGE_BIG_EXT: u8 = 111;
static ATOM_UTF8_EXT: u8 = 118;
static SMALL_ATOM_UTF8_EXT: u8 = 119;
static NEW_FLOAT_EXT: u8 = 70;

#[derive(Debug, PartialEq)]
pub enum BertTerm {
    Int(i32),
    BigInt(bigint::BigInt),
    Float(f64),
    Atom(String),
    Tuple(Vec<BertTerm>),
    List(Vec<BertTerm>),
    String(Vec<u8>),
    Binary(Vec<u8>)
}

impl fmt::Display for BertTerm {
    #[allow(unused_must_use)]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            BertTerm::Int(n) => { write!(f, "{}", n) }
            BertTerm::BigInt(ref n) => { write!(f, "{}", n) }
            BertTerm::Float(x) => { write!(f, "{}", x) }
            BertTerm::Atom(ref s) => { write!(f, "{}", s) }
            BertTerm::Tuple(ref ts) => {
                write!(f, "{}", '{');
                let mut first = true;
                for t in ts {
                    if !first { write!(f, ", "); }
                    write!(f, "{}", t);
                    first = false;
                }
                write!(f, "{}", '}')
            }
            BertTerm::List(ref ts) => {
                write!(f, "[");
                let mut first = true;
                for t in ts {
                    if !first { write!(f, ", "); }
                    write!(f, "{}", t);
                    first = false;
                }
                write!(f, "]")
            }
            BertTerm::String(ref bytes) => {
                write!(f, "\"");
                for &b in bytes {
                    if b >= 0x20 && b <= 0x7e {
                        write!(f, "{}", b as char);
                    } else {
                        write!(f, "\\x{:x}", b);
                    }
                }
                write!(f, "\"")
            }
            BertTerm::Binary(ref bytes) => {
                write!(f, "<<");
                let mut first = true;
                for b in bytes {
                    if !first { write!(f, ", "); }
                    write!(f, "{}", b);
                    first = false;
                }
                write!(f, ">>")
            }
        }
    }
}

#[derive(Debug)]
pub enum BertError {
    Unknown,
    InvalidMagicNumber
}

named!(bert_magic_number, tag!([BERT_MAGIC_NUMBER]));

fn small_integer(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_INTEGER_EXT]));
    let (i, n) = try_parse!(i, nom::be_u8);
    IResult::Done(i, BertTerm::Int(n as i32))
}

fn integer(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([INTEGER_EXT]));
    let (i, n) = try_parse!(i, nom::be_i32);
    IResult::Done(i, BertTerm::Int(n))
}

fn atom(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([ATOM_EXT]));
    let (i, len) = try_parse!(i, nom::be_u16);
    let (i, atom_name) = try_parse!(i, take_str!(len));
    IResult::Done(i, BertTerm::Atom(atom_name.to_string()))
}

fn small_atom_utf8(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_ATOM_UTF8_EXT]));
    let (i, len) = try_parse!(i, nom::be_u8);
    let (i, atom_name) = try_parse!(i, take_str!(len));
    IResult::Done(i, BertTerm::Atom(atom_name.to_string()))
}

fn atom_utf8(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([ATOM_UTF8_EXT]));
    let (i, len) = try_parse!(i, nom::be_u16);
    let (i, atom_name) = try_parse!(i, take_str!(len));
    IResult::Done(i, BertTerm::Atom(atom_name.to_string()))
}

fn small_tuple(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_TUPLE_EXT]));
    let (i, arity) = try_parse!(i, nom::be_u8);
    let (i, tuple) = try_parse!(i, count!(bert_term, arity as usize));
    IResult::Done(i, BertTerm::Tuple(tuple))
}

fn large_tuple(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([LARGE_TUPLE_EXT]));
    let (i, arity) = try_parse!(i, nom::be_u32);
    let (i, tuple) = try_parse!(i, count!(bert_term, arity as usize));
    IResult::Done(i, BertTerm::Tuple(tuple))
}

fn nil(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([NIL_EXT]));
    IResult::Done(i, BertTerm::List(vec![]))
}

fn string(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([STRING_EXT]));
    let (i, len) = try_parse!(i, nom::be_u16);
    let (i, bytes) = try_parse!(i, count!(nom::be_u8, len as usize));
    IResult::Done(i, BertTerm::String(bytes))
}

fn list(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([LIST_EXT]));
    let (i, len) = try_parse!(i, nom::be_u32);
    let (i, mut elements) = try_parse!(i, count!(bert_term, len as usize));
    let (i, tail) = try_parse!(i, bert_term);
    match tail {
        BertTerm::List(_) => (),
        last_term => { elements.push(last_term); }
    };
    IResult::Done(i, BertTerm::List(elements))
}

fn binary(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([BINARY_EXT]));
    let (i, len) = try_parse!(i, nom::be_u32);
    let (i, elements) = try_parse!(i, count!(nom::be_u8, len as usize));
    IResult::Done(i, BertTerm::Binary(elements))
}

fn is_zero(b: u8) -> bool { b == 0 }
fn is_non_zero(b: u8) -> bool { b != 0 }

fn old_float(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([FLOAT_EXT]));
    let (i, bytes) = try_parse!(i, take_while!(is_non_zero));
    let (i, _) = try_parse!(i, take_while!(is_zero));
    let mut s = String::new();
    for b in bytes { s.push(*b as char); }
    let f = s.parse::<f64>().unwrap();
    IResult::Done(i, BertTerm::Float(f))
}

fn new_float(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([NEW_FLOAT_EXT]));
    let (i, raw_bytes) = try_parse!(i, nom::be_u64);
    let f: f64 = unsafe { mem::transmute(raw_bytes) };
    IResult::Done(i, BertTerm::Float(f))
}

fn compute_big_int(is_negative: bool, digits: &[u8]) -> bigint::BigInt {
    let mut sum: bigint::BigInt = Zero::zero();
    let mut pos: bigint::BigInt = One::one();
    for d in digits {
        let t = &pos * &(d.to_bigint().unwrap());
        sum = sum + &t;
        pos = pos * (256).to_bigint().unwrap();
    }
    if is_negative { sum = -sum; }
    return sum;
}

fn small_big_int(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_BIG_EXT]));
    let (i, len) = try_parse!(i, nom::be_u8);
    let (i, sign) = try_parse!(i, nom::be_u8);
    let (i, digits) = try_parse!(i, take!(len as usize));
    let b = compute_big_int(sign == 1, &digits);
    IResult::Done(i, BertTerm::BigInt(b))
}

fn large_big_int(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([LARGE_BIG_EXT]));
    let (i, len) = try_parse!(i, nom::be_u32);
    let (i, sign) = try_parse!(i, nom::be_u8);
    let (i, digits) = try_parse!(i, take!(len as usize));
    let b = compute_big_int(sign == 1, &digits);
    IResult::Done(i, BertTerm::BigInt(b))
}

named!(bert_term<&[u8], BertTerm>,
       alt!(small_integer
            | integer
            | atom
            | small_atom_utf8
            | atom_utf8
            | small_tuple
            | large_tuple
            | nil
            | list
            | string
            | binary
            | old_float
            | new_float
            | small_big_int
            | large_big_int
       )
);

pub fn parse(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, bert_magic_number);
    let (i, t) = try_parse!(i, bert_term);
    IResult::Done(i, t)
}

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

    #[test]
    fn test_small_integer() {
        for i in 0 .. u8::max_value() {
            let buf = &[SMALL_INTEGER_EXT, i];
            let t = small_integer(buf);
            assert_eq!(t, IResult::Done(&b""[..], BertTerm::Int(i as i32)));
        }
    }

    #[test]
    fn test_integer() {
        let buf0 = &[INTEGER_EXT, 0, 0, 0, 1];
        let buf1 = &[INTEGER_EXT, 0, 0, 1, 0];
        let buf2 = &[INTEGER_EXT, 0, 1, 0, 0];
        let buf3 = &[INTEGER_EXT, 1, 0, 0, 0];

        assert_eq!(integer(buf0), IResult::Done(&b""[..], BertTerm::Int(1)));
        assert_eq!(integer(buf1), IResult::Done(&b""[..], BertTerm::Int(1 << 8)));
        assert_eq!(integer(buf2), IResult::Done(&b""[..], BertTerm::Int(1 << 16)));
        assert_eq!(integer(buf3), IResult::Done(&b""[..], BertTerm::Int(1 << 24)));
    }

    #[test]
    fn test_atom() {
        let buf = &[ATOM_EXT, 0, 2, b'a', b'b'];
        assert_eq!(atom(buf), IResult::Done(&b""[..], BertTerm::Atom("ab".to_string())));
    }

    #[test]
    fn test_small_tuple() {
        let buf = &[SMALL_TUPLE_EXT, 2, ATOM_EXT, 0, 2, b'o', b'k', SMALL_INTEGER_EXT, 42];
        assert_eq!(small_tuple(buf),
                   IResult::Done(&b""[..],
                                 BertTerm::Tuple(vec![BertTerm::Atom("ok".to_string()),
                                                      BertTerm::Int(42)])));
    }

    #[test]
    fn test_nil() {
        let buf = &[NIL_EXT];
        assert_eq!(nil(buf), IResult::Done(&b""[..], BertTerm::List(vec![])));
    }

    #[test]
    fn string_test() {
        use self::BertTerm::*;
        let buf = &[STRING_EXT, 0, 5, b'h', b'e', b'l', b'l', b'o'];
        assert_eq!(string(buf),
                   IResult::Done(&b""[..], String(vec![104, 101, 108, 108, 111])));
    }

    #[test]
    fn test_list() {
        use self::BertTerm::*;
        let buf0 = &[
            LIST_EXT, 0, 0, 0, 2,
            SMALL_INTEGER_EXT, 42,
            INTEGER_EXT, 0, 1, 0, 0,
            NIL_EXT
        ];
        let buf1 = &[
            LIST_EXT, 0, 0, 0, 2,
            SMALL_INTEGER_EXT, 42,
            INTEGER_EXT, 0, 1, 0, 0,
            SMALL_INTEGER_EXT, 84
        ];
        assert_eq!(list(buf0), IResult::Done(&b""[..], List(vec![Int(42), Int(65536)])));
        assert_eq!(list(buf1), IResult::Done(&b""[..], List(vec![Int(42), Int(65536), Int(84)])));
    }

    #[test]
    fn binary_test() {
        let buf = &[BINARY_EXT, 0, 0, 0, 4, 1, 3, 3, 7];
        assert_eq!(binary(buf), IResult::Done(&b""[..], BertTerm::Binary(vec![1,3,3,7])));
    }

}
<commit_msg>Add function fmt_separated_by<commit_after>extern crate nom;
extern crate num;

use std::mem;
use std::fmt;

use nom::{IResult, ErrorKind};
use num::bigint;
use num::bigint::ToBigInt;
use num::traits::{Zero, One};

static BERT_MAGIC_NUMBER: u8 = 131;
static SMALL_INTEGER_EXT: u8 = 97;
static INTEGER_EXT: u8 = 98;
static FLOAT_EXT: u8 = 99;
static ATOM_EXT: u8 = 100;
static SMALL_TUPLE_EXT: u8 = 104;
static LARGE_TUPLE_EXT: u8 = 105;
static NIL_EXT: u8 = 106;
static STRING_EXT: u8 = 107;
static LIST_EXT: u8 = 108;
static BINARY_EXT: u8 = 109;
static SMALL_BIG_EXT: u8 = 110;
static LARGE_BIG_EXT: u8 = 111;
static ATOM_UTF8_EXT: u8 = 118;
static SMALL_ATOM_UTF8_EXT: u8 = 119;
static NEW_FLOAT_EXT: u8 = 70;

#[derive(Debug, PartialEq)]
pub enum BertTerm {
    Int(i32),
    BigInt(bigint::BigInt),
    Float(f64),
    Atom(String),
    Tuple(Vec<BertTerm>),
    List(Vec<BertTerm>),
    String(Vec<u8>),
    Binary(Vec<u8>)
}

fn fmt_separated_by<T: fmt::Display>(f: &mut fmt::Formatter, terms: &[T], sep: &str) {
    let mut first = true;
    for t in terms {
        if !first { let _ = write!(f, "{}", sep); }
        let _ = write!(f, "{}", t);
        first = false;
    }
}

impl fmt::Display for BertTerm {
    #[allow(unused_must_use)]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            BertTerm::Int(n) => { write!(f, "{}", n) }
            BertTerm::BigInt(ref n) => { write!(f, "{}", n) }
            BertTerm::Float(x) => { write!(f, "{}", x) }
            BertTerm::Atom(ref s) => { write!(f, "{}", s) }
            BertTerm::Tuple(ref ts) => {
                write!(f, "{}", '{');
                fmt_separated_by(f, ts, ", ");
                write!(f, "{}", '}')
            }
            BertTerm::List(ref ts) => {
                write!(f, "[");
                let mut first = true;
                fmt_separated_by(f, ts, ", ");
                write!(f, "]")
            }
            BertTerm::String(ref bytes) => {
                write!(f, "\"");
                for &b in bytes {
                    if b >= 0x20 && b <= 0x7e {
                        write!(f, "{}", b as char);
                    } else {
                        write!(f, "\\x{:x}", b);
                    }
                }
                write!(f, "\"")
            }
            BertTerm::Binary(ref bytes) => {
                write!(f, "<<");
                fmt_separated_by(f, bytes, ", ");
                write!(f, ">>")
            }
        }
    }
}

#[derive(Debug)]
pub enum BertError {
    Unknown,
    InvalidMagicNumber
}

named!(bert_magic_number, tag!([BERT_MAGIC_NUMBER]));

fn small_integer(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_INTEGER_EXT]));
    let (i, n) = try_parse!(i, nom::be_u8);
    IResult::Done(i, BertTerm::Int(n as i32))
}

fn integer(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([INTEGER_EXT]));
    let (i, n) = try_parse!(i, nom::be_i32);
    IResult::Done(i, BertTerm::Int(n))
}

fn atom(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([ATOM_EXT]));
    let (i, len) = try_parse!(i, nom::be_u16);
    let (i, atom_name) = try_parse!(i, take_str!(len));
    IResult::Done(i, BertTerm::Atom(atom_name.to_string()))
}

fn small_atom_utf8(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_ATOM_UTF8_EXT]));
    let (i, len) = try_parse!(i, nom::be_u8);
    let (i, atom_name) = try_parse!(i, take_str!(len));
    IResult::Done(i, BertTerm::Atom(atom_name.to_string()))
}

fn atom_utf8(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([ATOM_UTF8_EXT]));
    let (i, len) = try_parse!(i, nom::be_u16);
    let (i, atom_name) = try_parse!(i, take_str!(len));
    IResult::Done(i, BertTerm::Atom(atom_name.to_string()))
}

fn small_tuple(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_TUPLE_EXT]));
    let (i, arity) = try_parse!(i, nom::be_u8);
    let (i, tuple) = try_parse!(i, count!(bert_term, arity as usize));
    IResult::Done(i, BertTerm::Tuple(tuple))
}

fn large_tuple(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([LARGE_TUPLE_EXT]));
    let (i, arity) = try_parse!(i, nom::be_u32);
    let (i, tuple) = try_parse!(i, count!(bert_term, arity as usize));
    IResult::Done(i, BertTerm::Tuple(tuple))
}

fn nil(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([NIL_EXT]));
    IResult::Done(i, BertTerm::List(vec![]))
}

fn string(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([STRING_EXT]));
    let (i, len) = try_parse!(i, nom::be_u16);
    let (i, bytes) = try_parse!(i, count!(nom::be_u8, len as usize));
    IResult::Done(i, BertTerm::String(bytes))
}

fn list(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([LIST_EXT]));
    let (i, len) = try_parse!(i, nom::be_u32);
    let (i, mut elements) = try_parse!(i, count!(bert_term, len as usize));
    let (i, tail) = try_parse!(i, bert_term);
    match tail {
        BertTerm::List(_) => (),
        last_term => { elements.push(last_term); }
    };
    IResult::Done(i, BertTerm::List(elements))
}

fn binary(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([BINARY_EXT]));
    let (i, len) = try_parse!(i, nom::be_u32);
    let (i, elements) = try_parse!(i, count!(nom::be_u8, len as usize));
    IResult::Done(i, BertTerm::Binary(elements))
}

fn is_zero(b: u8) -> bool { b == 0 }
fn is_non_zero(b: u8) -> bool { b != 0 }

fn old_float(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([FLOAT_EXT]));
    let (i, bytes) = try_parse!(i, take_while!(is_non_zero));
    let (i, _) = try_parse!(i, take_while!(is_zero));
    let mut s = String::new();
    for b in bytes { s.push(*b as char); }
    let f = s.parse::<f64>().unwrap();
    IResult::Done(i, BertTerm::Float(f))
}

fn new_float(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([NEW_FLOAT_EXT]));
    let (i, raw_bytes) = try_parse!(i, nom::be_u64);
    let f: f64 = unsafe { mem::transmute(raw_bytes) };
    IResult::Done(i, BertTerm::Float(f))
}

fn compute_big_int(is_negative: bool, digits: &[u8]) -> bigint::BigInt {
    let mut sum: bigint::BigInt = Zero::zero();
    let mut pos: bigint::BigInt = One::one();
    for d in digits {
        let t = &pos * &(d.to_bigint().unwrap());
        sum = sum + &t;
        pos = pos * (256).to_bigint().unwrap();
    }
    if is_negative { sum = -sum; }
    return sum;
}

fn small_big_int(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_BIG_EXT]));
    let (i, len) = try_parse!(i, nom::be_u8);
    let (i, sign) = try_parse!(i, nom::be_u8);
    let (i, digits) = try_parse!(i, take!(len as usize));
    let b = compute_big_int(sign == 1, &digits);
    IResult::Done(i, BertTerm::BigInt(b))
}

fn large_big_int(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([LARGE_BIG_EXT]));
    let (i, len) = try_parse!(i, nom::be_u32);
    let (i, sign) = try_parse!(i, nom::be_u8);
    let (i, digits) = try_parse!(i, take!(len as usize));
    let b = compute_big_int(sign == 1, &digits);
    IResult::Done(i, BertTerm::BigInt(b))
}

named!(bert_term<&[u8], BertTerm>,
       alt!(small_integer
            | integer
            | atom
            | small_atom_utf8
            | atom_utf8
            | small_tuple
            | large_tuple
            | nil
            | list
            | string
            | binary
            | old_float
            | new_float
            | small_big_int
            | large_big_int
       )
);

pub fn parse(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, bert_magic_number);
    let (i, t) = try_parse!(i, bert_term);
    IResult::Done(i, t)
}

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

    #[test]
    fn test_small_integer() {
        for i in 0 .. u8::max_value() {
            let buf = &[SMALL_INTEGER_EXT, i];
            let t = small_integer(buf);
            assert_eq!(t, IResult::Done(&b""[..], BertTerm::Int(i as i32)));
        }
    }

    #[test]
    fn test_integer() {
        let buf0 = &[INTEGER_EXT, 0, 0, 0, 1];
        let buf1 = &[INTEGER_EXT, 0, 0, 1, 0];
        let buf2 = &[INTEGER_EXT, 0, 1, 0, 0];
        let buf3 = &[INTEGER_EXT, 1, 0, 0, 0];

        assert_eq!(integer(buf0), IResult::Done(&b""[..], BertTerm::Int(1)));
        assert_eq!(integer(buf1), IResult::Done(&b""[..], BertTerm::Int(1 << 8)));
        assert_eq!(integer(buf2), IResult::Done(&b""[..], BertTerm::Int(1 << 16)));
        assert_eq!(integer(buf3), IResult::Done(&b""[..], BertTerm::Int(1 << 24)));
    }

    #[test]
    fn test_atom() {
        let buf = &[ATOM_EXT, 0, 2, b'a', b'b'];
        assert_eq!(atom(buf), IResult::Done(&b""[..], BertTerm::Atom("ab".to_string())));
    }

    #[test]
    fn test_small_tuple() {
        let buf = &[SMALL_TUPLE_EXT, 2, ATOM_EXT, 0, 2, b'o', b'k', SMALL_INTEGER_EXT, 42];
        assert_eq!(small_tuple(buf),
                   IResult::Done(&b""[..],
                                 BertTerm::Tuple(vec![BertTerm::Atom("ok".to_string()),
                                                      BertTerm::Int(42)])));
    }

    #[test]
    fn test_nil() {
        let buf = &[NIL_EXT];
        assert_eq!(nil(buf), IResult::Done(&b""[..], BertTerm::List(vec![])));
    }

    #[test]
    fn string_test() {
        use self::BertTerm::*;
        let buf = &[STRING_EXT, 0, 5, b'h', b'e', b'l', b'l', b'o'];
        assert_eq!(string(buf),
                   IResult::Done(&b""[..], String(vec![104, 101, 108, 108, 111])));
    }

    #[test]
    fn test_list() {
        use self::BertTerm::*;
        let buf0 = &[
            LIST_EXT, 0, 0, 0, 2,
            SMALL_INTEGER_EXT, 42,
            INTEGER_EXT, 0, 1, 0, 0,
            NIL_EXT
        ];
        let buf1 = &[
            LIST_EXT, 0, 0, 0, 2,
            SMALL_INTEGER_EXT, 42,
            INTEGER_EXT, 0, 1, 0, 0,
            SMALL_INTEGER_EXT, 84
        ];
        assert_eq!(list(buf0), IResult::Done(&b""[..], List(vec![Int(42), Int(65536)])));
        assert_eq!(list(buf1), IResult::Done(&b""[..], List(vec![Int(42), Int(65536), Int(84)])));
    }

    #[test]
    fn binary_test() {
        let buf = &[BINARY_EXT, 0, 0, 0, 4, 1, 3, 3, 7];
        assert_eq!(binary(buf), IResult::Done(&b""[..], BertTerm::Binary(vec![1,3,3,7])));
    }

}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
#[macro_use]
extern crate log;
extern crate sputnikvm;

use sputnikvm::{read_hex, Gas};
use sputnikvm::vm::{Machine, FakeVectorMachine};

use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use log::LogLevel;

fn main() {
    let matches = clap_app!(svm =>
        (version: "0.1.0")
        (author: "SputnikVM Contributors")
        (about: "SputnikVM - Ethereum Classic Virtual Machine")
        (@arg GAS: -g --gas +takes_value +required "Sets the gas amount")
        (@arg DATA: -d --data +takes_value +required "Sets the data needed")
        (@arg CODE: -c --code +takes_value +required "Sets the path to a file which contains the vm byte code")
        (@arg STATS: -s --stats "Return statistics on the execution")
        (@arg debug: -D --debug ... "Sets the level of debugging information")
    ).get_matches();

    let code_hex = read_hex(match matches.value_of("CODE") {
        Some(c) => c,
        None => "",
    });

    let code = code_hex.expect("code must be provided");

    let initial_gas = (value_t!(matches, "GAS", isize).unwrap_or(0xff)).into();
    let data = match matches.value_of("DATA") {
        Some(d) => d.as_bytes().into(),
        None => "".as_bytes().into(),
    };

    let mut machine = FakeVectorMachine::new(code.as_slice(), data, initial_gas);
    machine.fire();
    if log_enabled!(LogLevel::Info) {
        info!("gas used: {:?}", machine.used_gas());
    }
}
<commit_msg>Problem: travis error in CLI Solution: new -> fake<commit_after>#[macro_use]
extern crate clap;
#[macro_use]
extern crate log;
extern crate sputnikvm;

use sputnikvm::{read_hex, Gas};
use sputnikvm::vm::{Machine, FakeVectorMachine};

use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use log::LogLevel;

fn main() {
    let matches = clap_app!(svm =>
        (version: "0.1.0")
        (author: "SputnikVM Contributors")
        (about: "SputnikVM - Ethereum Classic Virtual Machine")
        (@arg GAS: -g --gas +takes_value +required "Sets the gas amount")
        (@arg DATA: -d --data +takes_value +required "Sets the data needed")
        (@arg CODE: -c --code +takes_value +required "Sets the path to a file which contains the vm byte code")
        (@arg STATS: -s --stats "Return statistics on the execution")
        (@arg debug: -D --debug ... "Sets the level of debugging information")
    ).get_matches();

    let code_hex = read_hex(match matches.value_of("CODE") {
        Some(c) => c,
        None => "",
    });

    let code = code_hex.expect("code must be provided");

    let initial_gas = (value_t!(matches, "GAS", isize).unwrap_or(0xff)).into();
    let data = match matches.value_of("DATA") {
        Some(d) => d.as_bytes().into(),
        None => "".as_bytes().into(),
    };

    let mut machine = FakeVectorMachine::fake(code.as_slice(), data, initial_gas);
    machine.fire();
    if log_enabled!(LogLevel::Info) {
        info!("gas used: {:?}", machine.used_gas());
    }
}
<|endoftext|>