<commit_before>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! minigbm: implements swapchain allocation using ChromeOS's minigbm library.
//!
//! External code found at <https://chromium.googlesource.com/chromiumos/platform/minigbm>.

#![cfg(feature = "minigbm")]

use std::ffi::CStr;
use std::fs::File;
use std::io::Seek;
use std::io::SeekFrom;
use std::os::raw::c_char;
use std::sync::Arc;

use base::AsRawDescriptor;
use base::Error as BaseError;
use base::FromRawDescriptor;
use base::RawDescriptor;

use crate::rutabaga_gralloc::formats::DrmFormat;
use crate::rutabaga_gralloc::gralloc::Gralloc;
use crate::rutabaga_gralloc::gralloc::ImageAllocationInfo;
use crate::rutabaga_gralloc::gralloc::ImageMemoryRequirements;
use crate::rutabaga_gralloc::minigbm_bindings::*;
use crate::rutabaga_gralloc::rendernode;
use crate::rutabaga_utils::*;

struct MinigbmDeviceInner {
    fd: File,
    gbm: *mut gbm_device,
}

// Safe because minigbm handles synchronization internally.
unsafe impl Send for MinigbmDeviceInner {}
unsafe impl Sync for MinigbmDeviceInner {}

impl Drop for MinigbmDeviceInner {
    fn drop(&mut self) {
        // Safe because MinigbmDeviceInner is only constructed with a valid minigbm_device.
        unsafe {
            gbm_device_destroy(self.gbm);
        }
    }
}

/// A device capable of allocating `MinigbmBuffer`.
#[derive(Clone)]
pub struct MinigbmDevice {
    minigbm_device: Arc<MinigbmDeviceInner>,
    last_buffer: Option<Arc<MinigbmBuffer>>,
    device_name: &'static str,
}

impl MinigbmDevice {
    /// Returns a new `MinigbmDevice` if there is a rendernode in `/dev/dri/` that is accepted by
    /// the minigbm library.
    pub fn init() -> RutabagaResult<Box<dyn Gralloc>> {
        let undesired: &[&str] = &["vgem", "pvr"];
        let fd = rendernode::open_device(undesired)?;

        // gbm_create_device is safe to call with a valid fd, and we check that a valid one is
        // returned.  If the fd does not refer to a DRM device, gbm_create_device will reject it.
        let gbm = unsafe { gbm_create_device(fd.as_raw_descriptor()) };
        if gbm.is_null() {
            return Err(RutabagaError::BaseError(BaseError::last()));
        }

        // Safe because a valid minigbm device has a statically allocated string associated with
        // it, which is valid for the lifetime of the process.
        let backend_name: *const c_char = unsafe { gbm_device_get_backend_name(gbm) };
        let c_str: &CStr = unsafe { CStr::from_ptr(backend_name) };
        let device_name: &str = c_str.to_str()?;

        Ok(Box::new(MinigbmDevice {
            minigbm_device: Arc::new(MinigbmDeviceInner { fd, gbm }),
            last_buffer: None,
            device_name,
        }))
    }
}

impl Gralloc for MinigbmDevice {
    fn supports_external_gpu_memory(&self) -> bool {
        true
    }

    fn supports_dmabuf(&self) -> bool {
        true
    }

    fn get_image_memory_requirements(
        &mut self,
        info: ImageAllocationInfo,
    ) -> RutabagaResult<ImageMemoryRequirements> {
        let bo = unsafe {
            gbm_bo_create(
                self.minigbm_device.gbm,
                info.width,
                info.height,
                info.drm_format.0,
                info.flags.0,
            )
        };
        if bo.is_null() {
            return Err(RutabagaError::BaseError(BaseError::last()));
        }

        let mut reqs: ImageMemoryRequirements = Default::default();
        let gbm_buffer = MinigbmBuffer(bo, self.clone());

        // Intel GPUs typically only use cached memory buffers.  This will change with dGPUs, but
        // perhaps minigbm will be deprecated by then.  Other display drivers (rockchip, mediatek,
        // amdgpu) typically use write combine memory.  We can also consider use flags too if this
        // heuristic proves insufficient.
        if self.device_name == "i915" {
            reqs.map_info = RUTABAGA_MAP_CACHE_CACHED;
        } else {
            reqs.map_info = RUTABAGA_MAP_CACHE_WC;
        }

        reqs.modifier = gbm_buffer.format_modifier();
        for plane in 0..gbm_buffer.num_planes() {
            reqs.strides[plane] = gbm_buffer.plane_stride(plane);
            reqs.offsets[plane] = gbm_buffer.plane_offset(plane);
        }

        let mut fd = gbm_buffer.export()?;
        let size = fd.seek(SeekFrom::End(0))?;

        // minigbm does have the ability to query image requirements without allocating memory
        // via the TEST_ALLOC flag.  However, support has only been added in i915.  Until this
        // flag is supported everywhere, do the actual allocation here and stash it away.
        if self.last_buffer.is_some() {
            return Err(RutabagaError::AlreadyInUse);
        }

        self.last_buffer = Some(Arc::new(gbm_buffer));
        reqs.info = info;
        reqs.size = size;
        Ok(reqs)
    }

    fn allocate_memory(&mut self, reqs: ImageMemoryRequirements) -> RutabagaResult<RutabagaHandle> {
        let last_buffer = self.last_buffer.take();
        if let Some(gbm_buffer) = last_buffer {
            if gbm_buffer.width() != reqs.info.width
                || gbm_buffer.height() != reqs.info.height
                || gbm_buffer.format() != reqs.info.drm_format
            {
                return Err(RutabagaError::InvalidGrallocDimensions);
            }

            let dmabuf = gbm_buffer.export()?.into();
            return Ok(RutabagaHandle {
                os_handle: dmabuf,
                handle_type: RUTABAGA_MEM_HANDLE_TYPE_DMABUF,
            });
        }

        let bo = unsafe {
            gbm_bo_create(
                self.minigbm_device.gbm,
                reqs.info.width,
                reqs.info.height,
                reqs.info.drm_format.0,
                reqs.info.flags.0,
            )
        };

        if bo.is_null() {
            return Err(RutabagaError::BaseError(BaseError::last()));
        }

        let gbm_buffer = MinigbmBuffer(bo, self.clone());
        let dmabuf = gbm_buffer.export()?.into();
        Ok(RutabagaHandle {
            os_handle: dmabuf,
            handle_type: RUTABAGA_MEM_HANDLE_TYPE_DMABUF,
        })
    }
}

/// An allocation from a `MinigbmDevice`.
pub struct MinigbmBuffer(*mut gbm_bo, MinigbmDevice);

// Safe because minigbm handles synchronization internally.
unsafe impl Send for MinigbmBuffer {}
unsafe impl Sync for MinigbmBuffer {}

impl MinigbmBuffer {
    /// Width in pixels.
    pub fn width(&self) -> u32 {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { gbm_bo_get_width(self.0) }
    }

    /// Height in pixels.
    pub fn height(&self) -> u32 {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { gbm_bo_get_height(self.0) }
    }

    /// `DrmFormat` of the buffer.
    pub fn format(&self) -> DrmFormat {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { DrmFormat(gbm_bo_get_format(self.0)) }
    }

    /// DrmFormat modifier flags for the buffer.
    pub fn format_modifier(&self) -> u64 {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { gbm_bo_get_modifier(self.0) }
    }

    /// Number of planes present in this buffer.
    pub fn num_planes(&self) -> usize {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { gbm_bo_get_plane_count(self.0) as usize }
    }

    /// Offset in bytes for the given plane.
    pub fn plane_offset(&self, plane: usize) -> u32 {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { gbm_bo_get_offset(self.0, plane) }
    }

    /// Length in bytes of one row for the given plane.
    pub fn plane_stride(&self, plane: usize) -> u32 {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { gbm_bo_get_stride_for_plane(self.0, plane) }
    }

    /// Exports a new dmabuf/prime file descriptor.
    pub fn export(&self) -> RutabagaResult<File> {
        // This is always safe to call with a valid gbm_bo pointer.
        match unsafe { gbm_bo_get_fd(self.0) } {
            fd if fd >= 0 => {
                let dmabuf = unsafe { File::from_raw_descriptor(fd) };
                Ok(dmabuf)
            }
            ret => Err(RutabagaError::ComponentError(ret)),
        }
    }
}

impl Drop for MinigbmBuffer {
    fn drop(&mut self) {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { gbm_bo_destroy(self.0) }
    }
}
<commit_msg>rutabaga_gfx: Support for cached mappings on msm<commit_after>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! minigbm: implements swapchain allocation using ChromeOS's minigbm library.
//!
//! External code found at <https://chromium.googlesource.com/chromiumos/platform/minigbm>.

#![cfg(feature = "minigbm")]

use std::ffi::CStr;
use std::fs::File;
use std::io::Seek;
use std::io::SeekFrom;
use std::os::raw::c_char;
use std::sync::Arc;

use base::AsRawDescriptor;
use base::Error as BaseError;
use base::FromRawDescriptor;
use base::RawDescriptor;

use crate::rutabaga_gralloc::formats::DrmFormat;
use crate::rutabaga_gralloc::gralloc::Gralloc;
use crate::rutabaga_gralloc::gralloc::ImageAllocationInfo;
use crate::rutabaga_gralloc::gralloc::ImageMemoryRequirements;
use crate::rutabaga_gralloc::minigbm_bindings::*;
use crate::rutabaga_gralloc::rendernode;
use crate::rutabaga_utils::*;

struct MinigbmDeviceInner {
    fd: File,
    gbm: *mut gbm_device,
}

// Safe because minigbm handles synchronization internally.
unsafe impl Send for MinigbmDeviceInner {}
unsafe impl Sync for MinigbmDeviceInner {}

impl Drop for MinigbmDeviceInner {
    fn drop(&mut self) {
        // Safe because MinigbmDeviceInner is only constructed with a valid minigbm_device.
        unsafe {
            gbm_device_destroy(self.gbm);
        }
    }
}

/// A device capable of allocating `MinigbmBuffer`.
#[derive(Clone)]
pub struct MinigbmDevice {
    minigbm_device: Arc<MinigbmDeviceInner>,
    last_buffer: Option<Arc<MinigbmBuffer>>,
    device_name: &'static str,
}

impl MinigbmDevice {
    /// Returns a new `MinigbmDevice` if there is a rendernode in `/dev/dri/` that is accepted by
    /// the minigbm library.
    pub fn init() -> RutabagaResult<Box<dyn Gralloc>> {
        let undesired: &[&str] = &["vgem", "pvr"];
        let fd = rendernode::open_device(undesired)?;

        // gbm_create_device is safe to call with a valid fd, and we check that a valid one is
        // returned.  If the fd does not refer to a DRM device, gbm_create_device will reject it.
        let gbm = unsafe { gbm_create_device(fd.as_raw_descriptor()) };
        if gbm.is_null() {
            return Err(RutabagaError::BaseError(BaseError::last()));
        }

        // Safe because a valid minigbm device has a statically allocated string associated with
        // it, which is valid for the lifetime of the process.
        let backend_name: *const c_char = unsafe { gbm_device_get_backend_name(gbm) };
        let c_str: &CStr = unsafe { CStr::from_ptr(backend_name) };
        let device_name: &str = c_str.to_str()?;

        Ok(Box::new(MinigbmDevice {
            minigbm_device: Arc::new(MinigbmDeviceInner { fd, gbm }),
            last_buffer: None,
            device_name,
        }))
    }
}

impl Gralloc for MinigbmDevice {
    fn supports_external_gpu_memory(&self) -> bool {
        true
    }

    fn supports_dmabuf(&self) -> bool {
        true
    }

    fn get_image_memory_requirements(
        &mut self,
        info: ImageAllocationInfo,
    ) -> RutabagaResult<ImageMemoryRequirements> {
        let bo = unsafe {
            gbm_bo_create(
                self.minigbm_device.gbm,
                info.width,
                info.height,
                info.drm_format.0,
                info.flags.0,
            )
        };
        if bo.is_null() {
            return Err(RutabagaError::BaseError(BaseError::last()));
        }

        let mut reqs: ImageMemoryRequirements = Default::default();
        let gbm_buffer = MinigbmBuffer(bo, self.clone());

        // Intel GPUs typically only use cached memory buffers.  This will change with dGPUs, but
        // perhaps minigbm will be deprecated by then.  Other display drivers (rockchip, mediatek,
        // amdgpu) typically use write combine memory.  We can also consider use flags too if this
        // heuristic proves insufficient.
        //
        // Existing qcom devices use a mix of cached and WC buffers.  We don't *yet* have a good
        // way to differentiate, but https://patchwork.freedesktop.org/series/106847/ is a proposal
        // to fix that.  But existing devices without the FWB feature, the resulting mapping attrs
        // are the more restrictive of the combination for S1 and S2 mappings.  So if we map as
        // cached in S2 pgtables, but S1 has WC, then the result will be WC.
        if self.device_name == "i915" || self.device_name == "msm" {
            reqs.map_info = RUTABAGA_MAP_CACHE_CACHED;
        } else {
            reqs.map_info = RUTABAGA_MAP_CACHE_WC;
        }

        reqs.modifier = gbm_buffer.format_modifier();
        for plane in 0..gbm_buffer.num_planes() {
            reqs.strides[plane] = gbm_buffer.plane_stride(plane);
            reqs.offsets[plane] = gbm_buffer.plane_offset(plane);
        }

        let mut fd = gbm_buffer.export()?;
        let size = fd.seek(SeekFrom::End(0))?;

        // minigbm does have the ability to query image requirements without allocating memory
        // via the TEST_ALLOC flag.  However, support has only been added in i915.  Until this
        // flag is supported everywhere, do the actual allocation here and stash it away.
        if self.last_buffer.is_some() {
            return Err(RutabagaError::AlreadyInUse);
        }

        self.last_buffer = Some(Arc::new(gbm_buffer));
        reqs.info = info;
        reqs.size = size;
        Ok(reqs)
    }

    fn allocate_memory(&mut self, reqs: ImageMemoryRequirements) -> RutabagaResult<RutabagaHandle> {
        let last_buffer = self.last_buffer.take();
        if let Some(gbm_buffer) = last_buffer {
            if gbm_buffer.width() != reqs.info.width
                || gbm_buffer.height() != reqs.info.height
                || gbm_buffer.format() != reqs.info.drm_format
            {
                return Err(RutabagaError::InvalidGrallocDimensions);
            }

            let dmabuf = gbm_buffer.export()?.into();
            return Ok(RutabagaHandle {
                os_handle: dmabuf,
                handle_type: RUTABAGA_MEM_HANDLE_TYPE_DMABUF,
            });
        }

        let bo = unsafe {
            gbm_bo_create(
                self.minigbm_device.gbm,
                reqs.info.width,
                reqs.info.height,
                reqs.info.drm_format.0,
                reqs.info.flags.0,
            )
        };

        if bo.is_null() {
            return Err(RutabagaError::BaseError(BaseError::last()));
        }

        let gbm_buffer = MinigbmBuffer(bo, self.clone());
        let dmabuf = gbm_buffer.export()?.into();
        Ok(RutabagaHandle {
            os_handle: dmabuf,
            handle_type: RUTABAGA_MEM_HANDLE_TYPE_DMABUF,
        })
    }
}

/// An allocation from a `MinigbmDevice`.
pub struct MinigbmBuffer(*mut gbm_bo, MinigbmDevice);

// Safe because minigbm handles synchronization internally.
unsafe impl Send for MinigbmBuffer {}
unsafe impl Sync for MinigbmBuffer {}

impl MinigbmBuffer {
    /// Width in pixels.
    pub fn width(&self) -> u32 {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { gbm_bo_get_width(self.0) }
    }

    /// Height in pixels.
    pub fn height(&self) -> u32 {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { gbm_bo_get_height(self.0) }
    }

    /// `DrmFormat` of the buffer.
    pub fn format(&self) -> DrmFormat {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { DrmFormat(gbm_bo_get_format(self.0)) }
    }

    /// DrmFormat modifier flags for the buffer.
    pub fn format_modifier(&self) -> u64 {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { gbm_bo_get_modifier(self.0) }
    }

    /// Number of planes present in this buffer.
    pub fn num_planes(&self) -> usize {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { gbm_bo_get_plane_count(self.0) as usize }
    }

    /// Offset in bytes for the given plane.
    pub fn plane_offset(&self, plane: usize) -> u32 {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { gbm_bo_get_offset(self.0, plane) }
    }

    /// Length in bytes of one row for the given plane.
    pub fn plane_stride(&self, plane: usize) -> u32 {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { gbm_bo_get_stride_for_plane(self.0, plane) }
    }

    /// Exports a new dmabuf/prime file descriptor.
    pub fn export(&self) -> RutabagaResult<File> {
        // This is always safe to call with a valid gbm_bo pointer.
        match unsafe { gbm_bo_get_fd(self.0) } {
            fd if fd >= 0 => {
                let dmabuf = unsafe { File::from_raw_descriptor(fd) };
                Ok(dmabuf)
            }
            ret => Err(RutabagaError::ComponentError(ret)),
        }
    }
}

impl Drop for MinigbmBuffer {
    fn drop(&mut self) {
        // This is always safe to call with a valid gbm_bo pointer.
        unsafe { gbm_bo_destroy(self.0) }
    }
}
<|endoftext|>


<commit_before>use name::*;
use art::*;

/// Nominal, artful lists: Lists with names and articulation points
#[deriving(Show,Hash,PartialEq,Eq)]
pub enum List<T> {
    Nil,
    Cons(T, Box<List<T>>),
    Name(Name, Box<List<T>>),
    Art(Art<Box<List<T>>>)
}

pub fn copy<T>(list:List<T>) -> List<T>
where T:'static {
    match list {
        List::Nil         => List::Nil,
        List::Cons(hd,tl) => List::Cons(hd, box copy(*tl)),
        List::Art(art)    => copy(*force(art)),
        List::Name(nm,tl) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box copy(*tl)) ;
            List::Name(nm2, box List::Art(art))
        }
    }
}

pub fn map<T,S,F> (f:F, list:List<T>) -> List<S>
where T:'static, S:'static,
      F:Fn(T) -> S + 'static
{
    match list {
        List::Nil         => List::Nil,
        List::Cons(hd,tl) => List::Cons(f(hd), box map(f,*tl)),
        // - - - - - boilerplate cases - - - - - -
        List::Art(art)    => map(f,*force(art)),
        List::Name(nm,tl) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box map(f,*tl)) ;
            List::Name(nm2, box List::Art(art))
        }
    }
}

pub fn contract<F,G,T> (f:F, g:G, list:List<T>) -> List<T>
where T:'static,
      F:Fn(&T,&T) -> bool + 'static,
      G:Fn(T,T) -> T + 'static
{
    match list {
        List::Nil => List::Nil,
        List::Cons(hd1, box list) => {
            match list {
                List::Nil => List::Cons(hd1, box List::Nil),
                List::Cons(hd2, tl) => {
                    if f(&hd1,&hd2) {
                        List::Cons(g(hd1,hd2), box contract(f,g,*tl))
                    } else {
                        List::Cons(hd1, box contract(f, g, List::Cons(hd2, tl)))
                    } },
                // - - - - - boilerplate cases - - - - - -
                List::Art(art) => contract(f,g,List::Cons(hd1,force(art))),
                List::Name(nm, tl) => {
                    let (nm1,nm2) = fork(nm) ;
                    let art = nart!(nm1, box contract(f,g,List::Cons(hd1,tl))) ;
                    List::Name(nm2, box List::Art(art))
                }
            }
        },
        // - - - - - boilerplate cases - - - - - -
        List::Art(art)    => contract(f,g,*force(art)),
        List::Name(nm,tl) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box contract(f,g,*tl)) ;
            List::Name(nm2, box List::Art(art))
        },
    }
}

pub fn merge<T,Ord> (ord:Ord, list1:List<T>, list2:List<T>) -> List<T>
where T:'static,
      Ord: Fn(&T,&T) -> bool + 'static
{
    match (list1, list2) {
        (List::Nil, list2) => list2,
        (list1, List::Nil) => list1,
        (List::Cons(hd1,tl1),
         List::Cons(hd2,tl2)) =>
            if ord(&hd1,&hd2) {
                List::Cons(hd1, box merge(ord, *tl1, List::Cons(hd2,tl2)))
            } else {
                List::Cons(hd2, box merge(ord, List::Cons(hd1,tl1), *tl2))
            },
        // - - - - - boilerplate cases - - - - -
        (List::Name(nm,tl), list2) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box merge(ord, *tl, list2)) ;
            List::Name(nm2, box List::Art(art))
        },
        (list1, List::Name(nm,tl)) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box merge(ord, list1, *tl)) ;
            List::Name(nm2, box List::Art(art))
        },
        (List::Art(art), list2) => merge(ord, *force(art), list2),
        (list1, List::Art(art)) => merge(ord, list1, *force(art)),
    }
}

#[test]
pub fn construct_list () {
    let z : List<int> = List::Nil;
    let y : List<int> = List::Cons(1, box z);
    let x : List<int> = List::Art(cell(symbol(format!("two")), box y));
    let l : List<int> = List::Name(symbol(format!("one")), box x);
    println!("constructed list: {}", l);
}

// impl<T> List<T> {
//     /// Construct a new, empty list.
//     #[inline]
//     pub fn new() -> List<T> { Nil }
// }

// impl<T: Send + Sync> List<T> {
//     /// Create a list with one element in it.
//     #[inline]
//     pub fn singleton(n:Name,val: T) -> List<T> { Cons(val, Art::new(Nil)) }

//     /// Get the head of a list.
//     pub fn head(&self) -> Option<&T> {
//         match *self {
//             Nil => None,
//             Cons(ref head, _) => Some(head)
//         }
//     }

//     /// Get the tail of a list.
//     pub fn tail(&self) -> Option<Art<List<T>>> {
//         match *self {
//             Nil => None,
//             Cons(_, ref tail) => Some(tail.clone())
//         }
//     }

//     /// Get an iterator over the items in a list.
//     pub fn iter<'a>(&'a self) -> ListItems<'a, T> {
//         ListItems {
//             list: self
//         }
//     }
// }

// /// An iterator over the items in a list.
// pub struct ListItems<'a, T: 'a> {
//     list: &'a List<T>
// }

// impl<'a, T: Send + Sync> Iterator<&'a T> for ListItems<'a, T> {
//     fn next(&mut self) -> Option<&'a T> {
//         match *self.list {
//             Cons(ref head, ref tail) => {
//                 self.list = &**tail;
//                 Some(head)
//             },
//             Nil => None
//         }
//     }
// }

<commit_msg>wrote reduce; using borrows, not moves, for passing closures<commit_after>use name::*;
use art::*;

/// Nominal, artful lists: Lists with names and articulation points
#[deriving(Show,Hash,PartialEq,Eq)]
pub enum List<T> {
    Nil,
    Cons(T, Box<List<T>>),
    Name(Name, Box<List<T>>),
    Art(Art<Box<List<T>>>)
}

pub fn copy<T>(list:List<T>) -> List<T>
where T:'static {
    match list {
        List::Nil         => List::Nil,
        List::Cons(hd,tl) => List::Cons(hd, box copy(*tl)),
        List::Art(art)    => copy(*force(art)),
        List::Name(nm,tl) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box copy(*tl)) ;
            List::Name(nm2, box List::Art(art))
        }
    }
}

pub fn map<T,S,F> (f:&'static F, list:List<T>) -> List<S>
where T:'static, S:'static,
      F:Fn(T) -> S
{
    match list {
        List::Nil         => List::Nil,
        List::Cons(hd,tl) => List::Cons((*f)(hd), box map(f,*tl)),
        // - - - - - boilerplate cases - - - - - -
        List::Art(art)    => map(f,*force(art)),
        List::Name(nm,tl) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box map(f,*tl)) ;
            List::Name(nm2, box List::Art(art))
        }
    }
}

pub fn contract<F,G,T> (f:&'static F, g:&'static G, list:List<T>) -> List<T>
where T:'static,
      F:Fn(&T,&T) -> bool,
      G:Fn(T,T) -> T
{
    match list {
        List::Nil => List::Nil,
        List::Cons(hd1, box list) => {
            match list {
                List::Nil => List::Cons(hd1, box List::Nil),
                List::Cons(hd2, tl) => {
                    if (*f)(&hd1,&hd2) {
                        List::Cons((*g)(hd1,hd2), box contract(f,g,*tl))
                    } else {
                        List::Cons(hd1, box contract(f, g, List::Cons(hd2, tl)))
                    } },
                // - - - - - boilerplate cases - - - - - -
                List::Art(art) => contract(f,g,List::Cons(hd1,force(art))),
                List::Name(nm, tl) => {
                    let (nm1,nm2) = fork(nm) ;
                    let art = nart!(nm1, box contract(f,g,List::Cons(hd1,tl))) ;
                    List::Name(nm2, box List::Art(art))
                }
            }
        },
        // - - - - - boilerplate cases - - - - - -
        List::Art(art)    => contract(f,g,*force(art)),
        List::Name(nm,tl) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box contract(f,g,*tl)) ;
            List::Name(nm2, box List::Art(art))
        },
    }
}

pub fn reduce<F,G,T> (f:&'static F, g:&'static G, list:List<T>) -> Option<T>
where T:'static,
      F: Fn(&T,&T) -> bool + 'static,
      G: Fn(T, T) -> T + 'static
{
    match list {
        List::Nil => None,
        List::Cons(hd, box list) => {
            match list {
                List::Nil => Some(hd),
                List::Cons(hd2, tl) => {
                    let hd3 = (*g)(hd,hd2) ;
                    let list = contract(f, g, List::Cons(hd3, tl)) ;
                    reduce (f, g, list)
                },
                // - - - - - boilerplate cases - - - - - -
                List::Name(_,tl) => reduce (f, g, *tl),
                List::Art(art) => reduce (f, g, *force(art)),
            }},
        // - - - - - boilerplate cases - - - - - -
        List::Art(art)    => reduce(f, g, *force(art)),
        List::Name(_,tl) => reduce(f, g, *tl),
    }
}

pub fn merge<T,Ord> (ord:Ord, list1:List<T>, list2:List<T>) -> List<T>
where T:'static,
      Ord: Fn(&T,&T) -> bool + 'static
{
    match (list1, list2) {
        (List::Nil, list2) => list2,
        (list1, List::Nil) => list1,
        (List::Cons(hd1,tl1),
         List::Cons(hd2,tl2)) =>
            if ord(&hd1,&hd2) {
                List::Cons(hd1, box merge(ord, *tl1, List::Cons(hd2,tl2)))
            } else {
                List::Cons(hd2, box merge(ord, List::Cons(hd1,tl1), *tl2))
            },
        // - - - - - boilerplate cases - - - - -
        (List::Name(nm,tl), list2) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box merge(ord, *tl, list2)) ;
            List::Name(nm2, box List::Art(art))
        },
        (list1, List::Name(nm,tl)) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box merge(ord, list1, *tl)) ;
            List::Name(nm2, box List::Art(art))
        },
        (List::Art(art), list2) => merge(ord, *force(art), list2),
        (list1, List::Art(art)) => merge(ord, list1, *force(art)),
    }
}

#[test]
pub fn construct_list () {
    let z : List<int> = List::Nil;
    let y : List<int> = List::Cons(1, box z);
    let x : List<int> = List::Art(cell(symbol(format!("two")), box y));
    let l : List<int> = List::Name(symbol(format!("one")), box x);
    println!("constructed list: {}", l);
}

// impl<T> List<T> {
//     /// Construct a new, empty list.
//     #[inline]
//     pub fn new() -> List<T> { Nil }
// }

// impl<T: Send + Sync> List<T> {
//     /// Create a list with one element in it.
//     #[inline]
//     pub fn singleton(n:Name,val: T) -> List<T> { Cons(val, Art::new(Nil)) }

//     /// Get the head of a list.
//     pub fn head(&self) -> Option<&T> {
//         match *self {
//             Nil => None,
//             Cons(ref head, _) => Some(head)
//         }
//     }

//     /// Get the tail of a list.
//     pub fn tail(&self) -> Option<Art<List<T>>> {
//         match *self {
//             Nil => None,
//             Cons(_, ref tail) => Some(tail.clone())
//         }
//     }

//     /// Get an iterator over the items in a list.
//     pub fn iter<'a>(&'a self) -> ListItems<'a, T> {
//         ListItems {
//             list: self
//         }
//     }
// }

// /// An iterator over the items in a list.
// pub struct ListItems<'a, T: 'a> {
//     list: &'a List<T>
// }

// impl<'a, T: Send + Sync> Iterator<&'a T> for ListItems<'a, T> {
//     fn next(&mut self) -> Option<&'a T> {
//         match *self.list {
//             Cons(ref head, ref tail) => {
//                 self.list = &**tail;
//                 Some(head)
//             },
//             Nil => None
//         }
//     }
// }

<|endoftext|>


<commit_before>use super::bit::Bit;
use std::io::{Read, Bytes, Result};
use std::vec::Vec;

pub struct BitReader<R: Read> {
    bytes: Bytes<R>
}

impl<R: Read> BitReader<R> {
    fn new(inner: R) -> BitReader<R> {
        BitReader { bytes: inner.bytes() }
    }
}

impl<R: Read> BitReader<R> {
    fn read_bit(&mut self) -> Result<Bit>
    {
        Ok(Bit::Zero)
    }
}

struct MemReader {
    buffer: Vec<u8>,
    pos: u32
}

impl MemReader {
    fn new(buffer: Vec<u8>) -> MemReader {
        MemReader { buffer: buffer, pos: 0 }
    }
}
<commit_msg>this is where I start realizing that maybe putting tests into their own nested modules wasn't such a good idea<commit_after>use super::bit::Bit;
use std::io::{Read, Bytes, Result};
use std::vec::Vec;

pub struct BitReader<R: Read> {
    bytes: Bytes<R>
}

impl<R: Read> BitReader<R> {
    fn new(inner: R) -> BitReader<R> {
        BitReader { bytes: inner.bytes() }
    }
}

impl<R: Read> BitReader<R> {
    fn read_bit(&mut self) -> Result<Bit>
    {
        Ok(Bit::Zero)
    }
}

struct MemReader {
    buffer: Vec<u8>,
    pos: u32
}

impl MemReader {
    fn new(buffer: Vec<u8>) -> MemReader {
        MemReader { buffer: buffer, pos: 0 }
    }

    fn eof(&self) -> bool {
        true
    }
}

#[cfg(test)]
mod mem_reader_tests {
    use std::vec::Vec;
    use super::*;

    #[test]
    fn empty_eof() {
        assert!(MemReader::new(vec!()).eof());
    }
}
<|endoftext|>


<commit_before>use super::backend::Backend;
use super::super::buckets::Buckets;
use time;

#[derive(Debug)]
pub struct Console {
    last_flush_time: u64,
    last_flush_length: u64
}

impl Console {
    /// Create a Console formatter bound to any implementation
    /// of `std::io::Write`. The writer will be wrapped in a
    /// BufWriter.
    ///
    /// # Examples
    ///
    /// ```
    /// let cons = Console::new();
    /// ```
    pub fn new() -> Console {
        Console {
            last_flush_time: 0,
            last_flush_length: 0,
        }
    }

}

/// Print a single stats line.
fn fmt_line(key: &str, value: &f64) {
    println!("    {}: {}", key, value)
}

impl Backend for Console {
    fn flush_buckets(&mut self, buckets: &Buckets) {
        let now = time::get_time();
        println!("Flushing metrics: {}",
                 time::at(now).rfc822().to_string());

        println!("  counters:");
        for (key, value) in buckets.counters().iter() {
            fmt_line(&key, &value);
        }

        println!("  gauges:");
        for (key, value) in buckets.gauges().iter() {
            fmt_line(&key, &value);
        }

        println!("  timers:");
        for (key, values) in buckets.timers().iter() {
            println!("    {}: {:?}", key, values);
        }
    }
}
<commit_msg>Output internal metrics with console formatter.<commit_after>use super::backend::Backend;
use super::super::buckets::Buckets;
use time;

#[derive(Debug)]
pub struct Console {
    last_flush_time: u64,
    last_flush_length: u64
}

impl Console {
    /// Create a Console formatter bound to any implementation
    /// of `std::io::Write`. The writer will be wrapped in a
    /// BufWriter.
    ///
    /// # Examples
    ///
    /// ```
    /// let cons = Console::new();
    /// ```
    pub fn new() -> Console {
        Console {
            last_flush_time: 0,
            last_flush_length: 0,
        }
    }

}

/// Print a single stats line.
fn fmt_line(key: &str, value: &f64) {
    println!("    {}: {}", key, value)
}

impl Backend for Console {
    fn flush_buckets(&mut self, buckets: &Buckets) {
        let now = time::get_time();
        println!("Flushing metrics: {}",
                 time::at(now).rfc822().to_string());

        println!("  bad_messages: {}", buckets.bad_messages());
        println!("  total_messages: {}", buckets.total_messages());

        println!("  counters:");
        for (key, value) in buckets.counters().iter() {
            fmt_line(&key, &value);
        }

        println!("  gauges:");
        for (key, value) in buckets.gauges().iter() {
            fmt_line(&key, &value);
        }

        println!("  timers:");
        for (key, values) in buckets.timers().iter() {
            println!("    {}: {:?}", key, values);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax::{ast, ptr};
use syntax::codemap::Span;
use syntax::parse::classify;

use codemap::SpanUtils;
use expr::{block_contains_comment, is_simple_block, is_unsafe_block, rewrite_cond, ToExpr};
use items::{span_hi_for_arg, span_lo_for_arg};
use lists::{definitive_tactic, itemize_list, write_list, DefinitiveListTactic, ListFormatting,
            ListTactic, Separator, SeparatorPlace, SeparatorTactic};
use rewrite::{Rewrite, RewriteContext};
use shape::Shape;
use utils::{last_line_width, left_most_sub_expr, stmt_expr};

// This module is pretty messy because of the rules around closures and blocks:
// FIXME - the below is probably no longer true in full.
//   * if there is a return type, then there must be braces,
//   * given a closure with braces, whether that is parsed to give an inner block
//     or not depends on if there is a return type and if there are statements
//     in that block,
//   * if the first expression in the body ends with a block (i.e., is a
//     statement without needing a semi-colon), then adding or removing braces
//     can change whether it is treated as an expression or statement.

pub fn rewrite_closure(
    capture: ast::CaptureBy,
    fn_decl: &ast::FnDecl,
    body: &ast::Expr,
    span: Span,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    debug!("rewrite_closure {:?}", body);

    let (prefix, extra_offset) =
        rewrite_closure_fn_decl(capture, fn_decl, body, span, context, shape)?;
    // 1 = space between `|...|` and body.
    let body_shape = shape.offset_left(extra_offset)?;

    if let ast::ExprKind::Block(ref block) = body.node {
        // The body of the closure is an empty block.
        if block.stmts.is_empty() && !block_contains_comment(block, context.codemap) {
            return Some(format!("{} {{}}", prefix));
        }

        let result = match fn_decl.output {
            ast::FunctionRetTy::Default(_) => {
                try_rewrite_without_block(body, &prefix, context, shape, body_shape)
            }
            _ => None,
        };

        result.or_else(|| {
            // Either we require a block, or tried without and failed.
            rewrite_closure_block(block, &prefix, context, body_shape)
        })
    } else {
        rewrite_closure_expr(body, &prefix, context, body_shape).or_else(|| {
            // The closure originally had a non-block expression, but we can't fit on
            // one line, so we'll insert a block.
            rewrite_closure_with_block(body, &prefix, context, body_shape)
        })
    }
}

fn try_rewrite_without_block(
    expr: &ast::Expr,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
    body_shape: Shape,
) -> Option<String> {
    let expr = get_inner_expr(expr, prefix, context);

    if is_block_closure_forced(expr) {
        rewrite_closure_with_block(expr, prefix, context, shape)
    } else {
        rewrite_closure_expr(expr, prefix, context, body_shape)
    }
}

fn get_inner_expr<'a>(
    expr: &'a ast::Expr,
    prefix: &str,
    context: &RewriteContext,
) -> &'a ast::Expr {
    if let ast::ExprKind::Block(ref block) = expr.node {
        if !needs_block(block, prefix, context) {
            // block.stmts.len() == 1
            if let Some(expr) = stmt_expr(&block.stmts[0]) {
                return get_inner_expr(expr, prefix, context);
            }
        }
    }

    expr
}

// Figure out if a block is necessary.
fn needs_block(block: &ast::Block, prefix: &str, context: &RewriteContext) -> bool {
    is_unsafe_block(block) || block.stmts.len() > 1 || context.inside_macro
        || block_contains_comment(block, context.codemap) || prefix.contains('\n')
}

// Rewrite closure with a single expression wrapping its body with block.
fn rewrite_closure_with_block(
    body: &ast::Expr,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    let block = ast::Block {
        stmts: vec![
            ast::Stmt {
                id: ast::NodeId::new(0),
                node: ast::StmtKind::Expr(ptr::P(body.clone())),
                span: body.span,
            },
        ],
        id: ast::NodeId::new(0),
        rules: ast::BlockCheckMode::Default,
        span: body.span,
    };
    rewrite_closure_block(&block, prefix, context, shape)
}

// Rewrite closure with a single expression without wrapping its body with block.
fn rewrite_closure_expr(
    expr: &ast::Expr,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    let mut rewrite = expr.rewrite(context, shape);
    if classify::expr_requires_semi_to_be_stmt(left_most_sub_expr(expr)) {
        rewrite = and_one_line(rewrite);
    }
    rewrite = rewrite.and_then(|rw| {
        if context.config.multiline_closure_forces_block() && rw.contains('\n') {
            None
        } else {
            Some(rw)
        }
    });
    rewrite.map(|rw| format!("{} {}", prefix, rw))
}

// Rewrite closure whose body is block.
fn rewrite_closure_block(
    block: &ast::Block,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    let block_shape = shape.block();
    let block_str = block.rewrite(context, block_shape)?;
    Some(format!("{} {}", prefix, block_str))
}

// Return type is (prefix, extra_offset)
fn rewrite_closure_fn_decl(
    capture: ast::CaptureBy,
    fn_decl: &ast::FnDecl,
    body: &ast::Expr,
    span: Span,
    context: &RewriteContext,
    shape: Shape,
) -> Option<(String, usize)> {
    let mover = if capture == ast::CaptureBy::Value {
        "move "
    } else {
        ""
    };
    // 4 = "|| {".len(), which is overconservative when the closure consists of
    // a single expression.
    let nested_shape = shape.shrink_left(mover.len())?.sub_width(4)?;

    // 1 = |
    let argument_offset = nested_shape.indent + 1;
    let arg_shape = nested_shape.offset_left(1)?.visual_indent(0);
    let ret_str = fn_decl.output.rewrite(context, arg_shape)?;

    let arg_items = itemize_list(
        context.codemap,
        fn_decl.inputs.iter(),
        "|",
        ",",
        |arg| span_lo_for_arg(arg),
        |arg| span_hi_for_arg(context, arg),
        |arg| arg.rewrite(context, arg_shape),
        context.codemap.span_after(span, "|"),
        body.span.lo(),
        false,
    );
    let item_vec = arg_items.collect::<Vec<_>>();
    // 1 = space between arguments and return type.
    let horizontal_budget = nested_shape
        .width
        .checked_sub(ret_str.len() + 1)
        .unwrap_or(0);
    let tactic = definitive_tactic(
        &item_vec,
        ListTactic::HorizontalVertical,
        Separator::Comma,
        horizontal_budget,
    );
    let arg_shape = match tactic {
        DefinitiveListTactic::Horizontal => arg_shape.sub_width(ret_str.len() + 1)?,
        _ => arg_shape,
    };

    let fmt = ListFormatting {
        tactic: tactic,
        separator: ",",
        trailing_separator: SeparatorTactic::Never,
        separator_place: SeparatorPlace::Back,
        shape: arg_shape,
        ends_with_newline: false,
        preserve_newline: true,
        config: context.config,
    };
    let list_str = write_list(&item_vec, &fmt)?;
    let mut prefix = format!("{}|{}|", mover, list_str);

    if !ret_str.is_empty() {
        if prefix.contains('\n') {
            prefix.push('\n');
            prefix.push_str(&argument_offset.to_string(context.config));
        } else {
            prefix.push(' ');
        }
        prefix.push_str(&ret_str);
    }
    // 1 = space between `|...|` and body.
    let extra_offset = last_line_width(&prefix) + 1;

    Some((prefix, extra_offset))
}

// Rewriting closure which is placed at the end of the function call's arg.
// Returns `None` if the reformatted closure 'looks bad'.
pub fn rewrite_last_closure(
    context: &RewriteContext,
    expr: &ast::Expr,
    shape: Shape,
) -> Option<String> {
    if let ast::ExprKind::Closure(capture, ref fn_decl, ref body, _) = expr.node {
        let body = match body.node {
            ast::ExprKind::Block(ref block) if is_simple_block(block, context.codemap) => {
                stmt_expr(&block.stmts[0]).unwrap_or(body)
            }
            _ => body,
        };
        let (prefix, extra_offset) =
            rewrite_closure_fn_decl(capture, fn_decl, body, expr.span, context, shape)?;
        // If the closure goes multi line before its body, do not overflow the closure.
        if prefix.contains('\n') {
            return None;
        }
        // If we are inside macro, we do not want to add or remove block from closure body.
        if context.inside_macro {
            return expr.rewrite(context, shape);
        }

        let body_shape = shape.offset_left(extra_offset)?;

        // We force to use block for the body of the closure for certain kinds of expressions.
        if is_block_closure_forced(body) {
            return rewrite_closure_with_block(body, &prefix, context, body_shape).and_then(
                |body_str| {
                    // If the expression can fit in a single line, we need not force block closure.
                    if body_str.lines().count() <= 7 {
                        match rewrite_closure_expr(body, &prefix, context, shape) {
                            Some(ref single_line_body_str)
                                if !single_line_body_str.contains('\n') =>
                            {
                                Some(single_line_body_str.clone())
                            }
                            _ => Some(body_str),
                        }
                    } else {
                        Some(body_str)
                    }
                },
            );
        }

        // When overflowing the closure which consists of a single control flow expression,
        // force to use block if its condition uses multi line.
        let is_multi_lined_cond = rewrite_cond(context, body, body_shape)
            .map(|cond| cond.contains('\n') || cond.len() > body_shape.width)
            .unwrap_or(false);
        if is_multi_lined_cond {
            return rewrite_closure_with_block(body, &prefix, context, body_shape);
        }

        // Seems fine, just format the closure in usual manner.
        return expr.rewrite(context, shape);
    }
    None
}

/// Returns true if the given vector of arguments has more than one `ast::ExprKind::Closure`.
pub fn args_have_many_closure<T>(args: &[&T]) -> bool
where
    T: ToExpr,
{
    args.iter()
        .filter(|arg| {
            arg.to_expr()
                .map(|e| match e.node {
                    ast::ExprKind::Closure(..) => true,
                    _ => false,
                })
                .unwrap_or(false)
        })
        .count() > 1
}

fn is_block_closure_forced(expr: &ast::Expr) -> bool {
    match expr.node {
        ast::ExprKind::If(..)
        | ast::ExprKind::IfLet(..)
        | ast::ExprKind::Loop(..)
        | ast::ExprKind::While(..)
        | ast::ExprKind::WhileLet(..)
        | ast::ExprKind::ForLoop(..) => true,
        ast::ExprKind::AddrOf(_, ref expr)
        | ast::ExprKind::Box(ref expr)
        | ast::ExprKind::Try(ref expr)
        | ast::ExprKind::Unary(_, ref expr)
        | ast::ExprKind::Cast(ref expr, _) => is_block_closure_forced(expr),
        _ => false,
    }
}

fn and_one_line(x: Option<String>) -> Option<String> {
    x.and_then(|x| if x.contains('\n') { None } else { Some(x) })
}
<commit_msg>Do not squash unsafe block<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax::{ast, ptr};
use syntax::codemap::Span;
use syntax::parse::classify;

use codemap::SpanUtils;
use expr::{block_contains_comment, is_simple_block, is_unsafe_block, rewrite_cond, ToExpr};
use items::{span_hi_for_arg, span_lo_for_arg};
use lists::{definitive_tactic, itemize_list, write_list, DefinitiveListTactic, ListFormatting,
            ListTactic, Separator, SeparatorPlace, SeparatorTactic};
use rewrite::{Rewrite, RewriteContext};
use shape::Shape;
use utils::{last_line_width, left_most_sub_expr, stmt_expr};

// This module is pretty messy because of the rules around closures and blocks:
// FIXME - the below is probably no longer true in full.
//   * if there is a return type, then there must be braces,
//   * given a closure with braces, whether that is parsed to give an inner block
//     or not depends on if there is a return type and if there are statements
//     in that block,
//   * if the first expression in the body ends with a block (i.e., is a
//     statement without needing a semi-colon), then adding or removing braces
//     can change whether it is treated as an expression or statement.

pub fn rewrite_closure(
    capture: ast::CaptureBy,
    fn_decl: &ast::FnDecl,
    body: &ast::Expr,
    span: Span,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    debug!("rewrite_closure {:?}", body);

    let (prefix, extra_offset) =
        rewrite_closure_fn_decl(capture, fn_decl, body, span, context, shape)?;
    // 1 = space between `|...|` and body.
    let body_shape = shape.offset_left(extra_offset)?;

    if let ast::ExprKind::Block(ref block) = body.node {
        // The body of the closure is an empty block.
        if block.stmts.is_empty() && !block_contains_comment(block, context.codemap) {
            return Some(format!("{} {{}}", prefix));
        }

        let result = match fn_decl.output {
            ast::FunctionRetTy::Default(_) => {
                try_rewrite_without_block(body, &prefix, context, shape, body_shape)
            }
            _ => None,
        };

        result.or_else(|| {
            // Either we require a block, or tried without and failed.
            rewrite_closure_block(block, &prefix, context, body_shape)
        })
    } else {
        rewrite_closure_expr(body, &prefix, context, body_shape).or_else(|| {
            // The closure originally had a non-block expression, but we can't fit on
            // one line, so we'll insert a block.
            rewrite_closure_with_block(body, &prefix, context, body_shape)
        })
    }
}

fn try_rewrite_without_block(
    expr: &ast::Expr,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
    body_shape: Shape,
) -> Option<String> {
    let expr = get_inner_expr(expr, prefix, context);

    if is_block_closure_forced(expr) {
        rewrite_closure_with_block(expr, prefix, context, shape)
    } else {
        rewrite_closure_expr(expr, prefix, context, body_shape)
    }
}

fn get_inner_expr<'a>(
    expr: &'a ast::Expr,
    prefix: &str,
    context: &RewriteContext,
) -> &'a ast::Expr {
    if let ast::ExprKind::Block(ref block) = expr.node {
        if !needs_block(block, prefix, context) {
            // block.stmts.len() == 1
            if let Some(expr) = stmt_expr(&block.stmts[0]) {
                return get_inner_expr(expr, prefix, context);
            }
        }
    }

    expr
}

// Figure out if a block is necessary.
fn needs_block(block: &ast::Block, prefix: &str, context: &RewriteContext) -> bool {
    is_unsafe_block(block) || block.stmts.len() > 1 || context.inside_macro
        || block_contains_comment(block, context.codemap) || prefix.contains('\n')
}

// Rewrite closure with a single expression wrapping its body with block.
fn rewrite_closure_with_block(
    body: &ast::Expr,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    let block = ast::Block {
        stmts: vec![
            ast::Stmt {
                id: ast::NodeId::new(0),
                node: ast::StmtKind::Expr(ptr::P(body.clone())),
                span: body.span,
            },
        ],
        id: ast::NodeId::new(0),
        rules: ast::BlockCheckMode::Default,
        span: body.span,
    };
    rewrite_closure_block(&block, prefix, context, shape)
}

// Rewrite closure with a single expression without wrapping its body with block.
fn rewrite_closure_expr(
    expr: &ast::Expr,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    let mut rewrite = expr.rewrite(context, shape);
    if classify::expr_requires_semi_to_be_stmt(left_most_sub_expr(expr)) {
        rewrite = and_one_line(rewrite);
    }
    rewrite = rewrite.and_then(|rw| {
        if context.config.multiline_closure_forces_block() && rw.contains('\n') {
            None
        } else {
            Some(rw)
        }
    });
    rewrite.map(|rw| format!("{} {}", prefix, rw))
}

// Rewrite closure whose body is block.
fn rewrite_closure_block(
    block: &ast::Block,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    let block_shape = shape.block();
    let block_str = block.rewrite(context, block_shape)?;
    Some(format!("{} {}", prefix, block_str))
}

// Return type is (prefix, extra_offset)
fn rewrite_closure_fn_decl(
    capture: ast::CaptureBy,
    fn_decl: &ast::FnDecl,
    body: &ast::Expr,
    span: Span,
    context: &RewriteContext,
    shape: Shape,
) -> Option<(String, usize)> {
    let mover = if capture == ast::CaptureBy::Value {
        "move "
    } else {
        ""
    };
    // 4 = "|| {".len(), which is overconservative when the closure consists of
    // a single expression.
    let nested_shape = shape.shrink_left(mover.len())?.sub_width(4)?;

    // 1 = |
    let argument_offset = nested_shape.indent + 1;
    let arg_shape = nested_shape.offset_left(1)?.visual_indent(0);
    let ret_str = fn_decl.output.rewrite(context, arg_shape)?;

    let arg_items = itemize_list(
        context.codemap,
        fn_decl.inputs.iter(),
        "|",
        ",",
        |arg| span_lo_for_arg(arg),
        |arg| span_hi_for_arg(context, arg),
        |arg| arg.rewrite(context, arg_shape),
        context.codemap.span_after(span, "|"),
        body.span.lo(),
        false,
    );
    let item_vec = arg_items.collect::<Vec<_>>();
    // 1 = space between arguments and return type.
    let horizontal_budget = nested_shape
        .width
        .checked_sub(ret_str.len() + 1)
        .unwrap_or(0);
    let tactic = definitive_tactic(
        &item_vec,
        ListTactic::HorizontalVertical,
        Separator::Comma,
        horizontal_budget,
    );
    let arg_shape = match tactic {
        DefinitiveListTactic::Horizontal => arg_shape.sub_width(ret_str.len() + 1)?,
        _ => arg_shape,
    };

    let fmt = ListFormatting {
        tactic: tactic,
        separator: ",",
        trailing_separator: SeparatorTactic::Never,
        separator_place: SeparatorPlace::Back,
        shape: arg_shape,
        ends_with_newline: false,
        preserve_newline: true,
        config: context.config,
    };
    let list_str = write_list(&item_vec, &fmt)?;
    let mut prefix = format!("{}|{}|", mover, list_str);

    if !ret_str.is_empty() {
        if prefix.contains('\n') {
            prefix.push('\n');
            prefix.push_str(&argument_offset.to_string(context.config));
        } else {
            prefix.push(' ');
        }
        prefix.push_str(&ret_str);
    }
    // 1 = space between `|...|` and body.
    let extra_offset = last_line_width(&prefix) + 1;

    Some((prefix, extra_offset))
}

// Rewriting closure which is placed at the end of the function call's arg.
// Returns `None` if the reformatted closure 'looks bad'.
pub fn rewrite_last_closure(
    context: &RewriteContext,
    expr: &ast::Expr,
    shape: Shape,
) -> Option<String> {
    if let ast::ExprKind::Closure(capture, ref fn_decl, ref body, _) = expr.node {
        let body = match body.node {
            ast::ExprKind::Block(ref block)
                if !is_unsafe_block(block) && is_simple_block(block, context.codemap) =>
            {
                stmt_expr(&block.stmts[0]).unwrap_or(body)
            }
            _ => body,
        };
        let (prefix, extra_offset) =
            rewrite_closure_fn_decl(capture, fn_decl, body, expr.span, context, shape)?;
        // If the closure goes multi line before its body, do not overflow the closure.
        if prefix.contains('\n') {
            return None;
        }
        // If we are inside macro, we do not want to add or remove block from closure body.
        if context.inside_macro {
            return expr.rewrite(context, shape);
        }

        let body_shape = shape.offset_left(extra_offset)?;

        // We force to use block for the body of the closure for certain kinds of expressions.
        if is_block_closure_forced(body) {
            return rewrite_closure_with_block(body, &prefix, context, body_shape).and_then(
                |body_str| {
                    // If the expression can fit in a single line, we need not force block closure.
                    if body_str.lines().count() <= 7 {
                        match rewrite_closure_expr(body, &prefix, context, shape) {
                            Some(ref single_line_body_str)
                                if !single_line_body_str.contains('\n') =>
                            {
                                Some(single_line_body_str.clone())
                            }
                            _ => Some(body_str),
                        }
                    } else {
                        Some(body_str)
                    }
                },
            );
        }

        // When overflowing the closure which consists of a single control flow expression,
        // force to use block if its condition uses multi line.
        let is_multi_lined_cond = rewrite_cond(context, body, body_shape)
            .map(|cond| cond.contains('\n') || cond.len() > body_shape.width)
            .unwrap_or(false);
        if is_multi_lined_cond {
            return rewrite_closure_with_block(body, &prefix, context, body_shape);
        }

        // Seems fine, just format the closure in usual manner.
        return expr.rewrite(context, shape);
    }
    None
}

/// Returns true if the given vector of arguments has more than one `ast::ExprKind::Closure`.
pub fn args_have_many_closure<T>(args: &[&T]) -> bool
where
    T: ToExpr,
{
    args.iter()
        .filter(|arg| {
            arg.to_expr()
                .map(|e| match e.node {
                    ast::ExprKind::Closure(..) => true,
                    _ => false,
                })
                .unwrap_or(false)
        })
        .count() > 1
}

fn is_block_closure_forced(expr: &ast::Expr) -> bool {
    match expr.node {
        ast::ExprKind::If(..)
        | ast::ExprKind::IfLet(..)
        | ast::ExprKind::Loop(..)
        | ast::ExprKind::While(..)
        | ast::ExprKind::WhileLet(..)
        | ast::ExprKind::ForLoop(..) => true,
        ast::ExprKind::AddrOf(_, ref expr)
        | ast::ExprKind::Box(ref expr)
        | ast::ExprKind::Try(ref expr)
        | ast::ExprKind::Unary(_, ref expr)
        | ast::ExprKind::Cast(ref expr, _) => is_block_closure_forced(expr),
        _ => false,
    }
}

fn and_one_line(x: Option<String>) -> Option<String> {
    x.and_then(|x| if x.contains('\n') { None } else { Some(x) })
}
<|endoftext|>


<commit_before>/* Rustymine - Barebones Minecraft server in Rust
 *
 * Copyright (c) 2014 Ryan Mendivil <ryan@nullreff.net>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of Rustymine nor the names of its contributors may be
 *     used to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

use std::io::{Listener, Acceptor, IoResult, IoError, InvalidInput};
use std::io::net::tcp::{TcpListener, TcpStream};
use varint::{ReadVarint, ToVarint};
mod varint;

// Most of this was put together using http://wiki.vg/Protocoland Wireshark captures.
struct Packet {
    cmd: u8,
    value: PacketValue
}

enum PacketValue {
    Command,
    Data(Vec<u8>),
    Message(String)
}

trait PacketStream {
    fn read_packet_command(&mut self) -> IoResult<Packet>;
    fn read_packet_data(&mut self) -> IoResult<Packet>;
    fn read_packet_string(&mut self) -> IoResult<Packet>;
    fn write_packet(&mut self, packet: Packet) -> IoResult<()>;
}

impl Packet {
    fn len(& self) -> uint {
        match self.value {
            Command => 1,
            Data(ref data) => 1 + data.len(),
            Message(ref string) => {
                let len = string.len();
                1 + len + len.to_varint().len()
            }
        }
    }

    fn as_bytes(&self) -> Vec<u8> {
        let mut response = Vec::new();
        response.push_all(self.len().to_varint().as_slice());
        response.push(self.cmd);
        match self.value {
            Command => {},
            Data(ref data) => {
                response.push_all(data.as_slice());
            },
            Message(ref string) => {
                response.push_all(string.len().to_varint().as_slice());
                response.push_all(string.as_bytes());
            }
        }
        response
    }
}

impl PacketStream for TcpStream {
    fn read_packet_command(&mut self) -> IoResult<Packet> {
        let size = try!(self.read_varint());
        if size == 1 {
            let command = try!(self.read_byte());
            Ok(Packet {cmd: command, value: Command})
        } else {
            Err(IoError {
                kind: InvalidInput,
                desc: "Command packet with a size greater than one",
                detail: None
            })
        }
    }

    fn read_packet_data(&mut self) -> IoResult<Packet> {
        let size = try!(self.read_varint());
        if size == 0 {
            return Err(IoError {
                kind: InvalidInput,
                desc: "Data packet with size zero",
                detail: None
            });
        }
        let command = try!(self.read_byte());
        let data = try!(self.read_exact(size - 1));
        Ok(Packet {cmd: command, value: Data(data)})
    }

    fn read_packet_string(&mut self) -> IoResult<Packet> {
        try!(self.read_varint());
        let command = try!(self.read_byte());
        let string_size = try!(self.read_varint());
        let data = try!(self.read_exact(string_size));
        match std::str::from_utf8(data.as_slice()) {
            Some(string) => Ok(Packet {
                cmd: command,
                value: Message(string.to_string())
            }),
            None => Err(IoError {
                kind: InvalidInput,
                desc: "Command packet with a size greater than one",
                detail: None
            })
        }
    }

    fn write_packet(&mut self, packet: Packet) -> IoResult<()> {
        self.write(packet.as_bytes().as_slice())
    }
}

fn process_stream(mut stream: TcpStream) -> IoResult<()> {
    let message = "{\"description\":\"Rustymine Server\",\"players\":{\"max\":0,\"online\":0},\"version\":{\"name\":\"1.8\",\"protocol\":47}}";

    let ip = try!(stream.peer_name()).ip;
    let packet = try!(stream.read_packet_data());
    match packet {
        Packet { cmd: 0, value: Data(data) } => {
            match data[13] {
                // Query
                1 => {
                    println!("Query from {}", ip);

                    // We don't need anything from the second packet sent
                    try!(stream.read_packet_command());

                    // Send back the server status as JSON
                    try!(stream.write_packet(Packet {cmd: 0, value: Message(message.to_string())}));

                    // Then receive and respond to the ping packet
                    let ping = try!(stream.read_packet_data());
                    try!(stream.write_packet(ping));

                },
                // Login
                2 => {
                    match stream.read_packet_string() {
                        Ok(Packet {cmd: _, value: Message(name)}) => {
                            println!("Connection from {} ({})", name, ip);
                        },
                        _ => println!("Invalid login packet")
                    }

                },
                _ => println!("Invalid query packet")
            }
        },

        // Everything else
        _ => println!("Unknown packet")
    }
    Ok(())
}

fn main() {
    let mut acceptor = TcpListener::bind("0.0.0.0", 25565).listen().unwrap();
    println!("listening started, ready to accept");
    for opt_stream in acceptor.incoming() {
        spawn(proc() process_stream(opt_stream.unwrap()).unwrap())
    }
}
<commit_msg>Print info about address/port on startup<commit_after>/* Rustymine - Barebones Minecraft server in Rust
 *
 * Copyright (c) 2014 Ryan Mendivil <ryan@nullreff.net>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of Rustymine nor the names of its contributors may be
 *     used to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

use std::io::{Listener, Acceptor, IoResult, IoError, InvalidInput};
use std::io::net::tcp::{TcpListener, TcpStream};
use varint::{ReadVarint, ToVarint};
mod varint;

// Most of this was put together using http://wiki.vg/Protocoland Wireshark captures.
struct Packet {
    cmd: u8,
    value: PacketValue
}

enum PacketValue {
    Command,
    Data(Vec<u8>),
    Message(String)
}

trait PacketStream {
    fn read_packet_command(&mut self) -> IoResult<Packet>;
    fn read_packet_data(&mut self) -> IoResult<Packet>;
    fn read_packet_string(&mut self) -> IoResult<Packet>;
    fn write_packet(&mut self, packet: Packet) -> IoResult<()>;
}

impl Packet {
    fn len(& self) -> uint {
        match self.value {
            Command => 1,
            Data(ref data) => 1 + data.len(),
            Message(ref string) => {
                let len = string.len();
                1 + len + len.to_varint().len()
            }
        }
    }

    fn as_bytes(&self) -> Vec<u8> {
        let mut response = Vec::new();
        response.push_all(self.len().to_varint().as_slice());
        response.push(self.cmd);
        match self.value {
            Command => {},
            Data(ref data) => {
                response.push_all(data.as_slice());
            },
            Message(ref string) => {
                response.push_all(string.len().to_varint().as_slice());
                response.push_all(string.as_bytes());
            }
        }
        response
    }
}

impl PacketStream for TcpStream {
    fn read_packet_command(&mut self) -> IoResult<Packet> {
        let size = try!(self.read_varint());
        if size == 1 {
            let command = try!(self.read_byte());
            Ok(Packet {cmd: command, value: Command})
        } else {
            Err(IoError {
                kind: InvalidInput,
                desc: "Command packet with a size greater than one",
                detail: None
            })
        }
    }

    fn read_packet_data(&mut self) -> IoResult<Packet> {
        let size = try!(self.read_varint());
        if size == 0 {
            return Err(IoError {
                kind: InvalidInput,
                desc: "Data packet with size zero",
                detail: None
            });
        }
        let command = try!(self.read_byte());
        let data = try!(self.read_exact(size - 1));
        Ok(Packet {cmd: command, value: Data(data)})
    }

    fn read_packet_string(&mut self) -> IoResult<Packet> {
        try!(self.read_varint());
        let command = try!(self.read_byte());
        let string_size = try!(self.read_varint());
        let data = try!(self.read_exact(string_size));
        match std::str::from_utf8(data.as_slice()) {
            Some(string) => Ok(Packet {
                cmd: command,
                value: Message(string.to_string())
            }),
            None => Err(IoError {
                kind: InvalidInput,
                desc: "Command packet with a size greater than one",
                detail: None
            })
        }
    }

    fn write_packet(&mut self, packet: Packet) -> IoResult<()> {
        self.write(packet.as_bytes().as_slice())
    }
}

fn process_stream(mut stream: TcpStream) -> IoResult<()> {
    let message = "{\"description\":\"Rustymine Server\",\"players\":{\"max\":0,\"online\":0},\"version\":{\"name\":\"1.8\",\"protocol\":47}}";

    let ip = try!(stream.peer_name()).ip;
    let packet = try!(stream.read_packet_data());
    match packet {
        Packet { cmd: 0, value: Data(data) } => {
            match data[13] {
                // Query
                1 => {
                    println!("Query from {}", ip);

                    // We don't need anything from the second packet sent
                    try!(stream.read_packet_command());

                    // Send back the server status as JSON
                    try!(stream.write_packet(Packet {cmd: 0, value: Message(message.to_string())}));

                    // Then receive and respond to the ping packet
                    let ping = try!(stream.read_packet_data());
                    try!(stream.write_packet(ping));

                },
                // Login
                2 => {
                    match stream.read_packet_string() {
                        Ok(Packet {cmd: _, value: Message(name)}) => {
                            println!("Connection from {} ({})", name, ip);
                        },
                        _ => println!("Invalid login packet")
                    }

                },
                _ => println!("Invalid query packet")
            }
        },

        // Everything else
        _ => println!("Unknown packet")
    }
    Ok(())
}

fn main() {
    let address = "0.0.0.0";
    let port = 25565;
    let mut acceptor = TcpListener::bind(address, port).listen().unwrap();
    println!("Rustymine is listening on {}:{}", address, port);
    for opt_stream in acceptor.incoming() {
        spawn(proc() process_stream(opt_stream.unwrap()).unwrap())
    }
}
<|endoftext|>


<commit_before>use boxcars::crc::calc_crc;
use boxcars::*;
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};

fn bench_crc(c: &mut Criterion) {
    let data = include_bytes!("../assets/replays/good/rumble.replay");
    let mut group = c.benchmark_group("crc_throughput");
    group.throughput(Throughput::Bytes(data.len() as u64));
    group.bench_function("bench_crc", |b| {
        let data = include_bytes!("../assets/replays/good/rumble.replay");
        b.iter(|| {
            black_box(calc_crc(&data[..]));
        })
    });
    group.finish();
}

fn bench_json_serialization(c: &mut Criterion) {
    let data = include_bytes!("../assets/replays/good/3381.replay");
    let json_data_bytes = 19483077_u64;

    let mut group = c.benchmark_group("json_throughput");
    group.sample_size(10);
    group.throughput(Throughput::Bytes(json_data_bytes));
    group.bench_function("bench_json_serialization", |b| {
        let mut bytes = Vec::new();
        let replay = ParserBuilder::new(data)
            .on_error_check_crc()
            .parse()
            .unwrap();
        serde_json::to_writer(&mut bytes, &replay).unwrap();
        assert!(
            json_data_bytes == bytes.len() as u64,
            "update json benchmark with latest throughput size: {}",
            bytes.len()
        );
        unsafe {
            bytes.set_len(0);
        };

        b.iter(|| {
            black_box(serde_json::to_writer(&mut bytes, &replay).unwrap());
            unsafe {
                bytes.set_len(0);
            };
        })
    });
    group.finish();
}

fn bench_parse_crc_body(c: &mut Criterion) {
    let data = include_bytes!("../assets/replays/good/3381.replay");
    let mut group = c.benchmark_group("parse_crc_body");
    group.throughput(Throughput::Bytes(data.len() as u64));
    group.sample_size(20);
    group.bench_function("bench_parse_crc_body", |b| {
        b.iter(|| {
            black_box(
                ParserBuilder::new(data)
                    .always_check_crc()
                    .must_parse_network_data()
                    .parse()
                    .unwrap(),
            )
        });
    });
    group.finish();
}

fn bench_parse_no_crc_body(c: &mut Criterion) {
    let data = include_bytes!("../assets/replays/good/3381.replay");
    let mut group = c.benchmark_group("parse_no_crc_body");
    group.throughput(Throughput::Bytes(data.len() as u64));
    group.sample_size(20);
    group.bench_function("bench_parse_no_crc_body", |b| {
        b.iter(|| {
            black_box(
                ParserBuilder::new(data)
                    .on_error_check_crc()
                    .must_parse_network_data()
                    .parse()
                    .unwrap(),
            )
        });
    });
    group.finish();
}

fn bench_parse_no_crc_no_body(c: &mut Criterion) {
    // Throughput not included in this benchmark as it is a bit confusing what the number reporting
    // represents. If parsing the header reports based on the entire size of the replay, it will be
    // some very large number (20 GB/s), else it may look deceptively small
    let data = include_bytes!("../assets/replays/good/3381.replay");
    let mut group = c.benchmark_group("parse_no_crc_no_body");
    group.bench_function("bench_parse_no_crc_no_body", |b| {
        b.iter(|| {
            black_box(
                ParserBuilder::new(data)
                    .on_error_check_crc()
                    .never_parse_network_data()
                    .parse()
                    .unwrap(),
            )
        });
    });
    group.finish();
}

fn bench_parse_crc_json(c: &mut Criterion) {
    let data = include_bytes!("../assets/replays/good/3381.replay");
    let mut group = c.benchmark_group("parse_crc_json");
    group.throughput(Throughput::Bytes(data.len() as u64));
    group.sample_size(10);
    group.bench_function("bench_parse_crc_json", |b| {
        // allocate a buffer big enough to hold all of the serialized data
        let mut bytes = Vec::with_capacity(2_usize.pow(25));
        b.iter(|| {
            let data = ParserBuilder::new(data).always_check_crc().parse().unwrap();
            black_box(serde_json::to_writer(&mut bytes, &data).unwrap());
            unsafe {
                bytes.set_len(0);
            }
        });
    });
    group.finish();
}

criterion_group!(
    benches,
    bench_crc,
    bench_json_serialization,
    bench_parse_crc_body,
    bench_parse_no_crc_body,
    bench_parse_no_crc_no_body,
    bench_parse_crc_json,
);

criterion_main!(benches);
<commit_msg>Update json benchmark size<commit_after>use boxcars::crc::calc_crc;
use boxcars::*;
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};

fn bench_crc(c: &mut Criterion) {
    let data = include_bytes!("../assets/replays/good/rumble.replay");
    let mut group = c.benchmark_group("crc_throughput");
    group.throughput(Throughput::Bytes(data.len() as u64));
    group.bench_function("bench_crc", |b| {
        let data = include_bytes!("../assets/replays/good/rumble.replay");
        b.iter(|| {
            black_box(calc_crc(&data[..]));
        })
    });
    group.finish();
}

fn bench_json_serialization(c: &mut Criterion) {
    let data = include_bytes!("../assets/replays/good/3381.replay");
    let json_data_bytes = 19484480_u64;

    let mut group = c.benchmark_group("json_throughput");
    group.sample_size(10);
    group.throughput(Throughput::Bytes(json_data_bytes));
    group.bench_function("bench_json_serialization", |b| {
        let mut bytes = Vec::new();
        let replay = ParserBuilder::new(data)
            .on_error_check_crc()
            .parse()
            .unwrap();
        serde_json::to_writer(&mut bytes, &replay).unwrap();
        assert!(
            json_data_bytes == bytes.len() as u64,
            "update json benchmark with latest throughput size: {}",
            bytes.len()
        );
        unsafe {
            bytes.set_len(0);
        };

        b.iter(|| {
            black_box(serde_json::to_writer(&mut bytes, &replay).unwrap());
            unsafe {
                bytes.set_len(0);
            };
        })
    });
    group.finish();
}

fn bench_parse_crc_body(c: &mut Criterion) {
    let data = include_bytes!("../assets/replays/good/3381.replay");
    let mut group = c.benchmark_group("parse_crc_body");
    group.throughput(Throughput::Bytes(data.len() as u64));
    group.sample_size(20);
    group.bench_function("bench_parse_crc_body", |b| {
        b.iter(|| {
            black_box(
                ParserBuilder::new(data)
                    .always_check_crc()
                    .must_parse_network_data()
                    .parse()
                    .unwrap(),
            )
        });
    });
    group.finish();
}

fn bench_parse_no_crc_body(c: &mut Criterion) {
    let data = include_bytes!("../assets/replays/good/3381.replay");
    let mut group = c.benchmark_group("parse_no_crc_body");
    group.throughput(Throughput::Bytes(data.len() as u64));
    group.sample_size(20);
    group.bench_function("bench_parse_no_crc_body", |b| {
        b.iter(|| {
            black_box(
                ParserBuilder::new(data)
                    .on_error_check_crc()
                    .must_parse_network_data()
                    .parse()
                    .unwrap(),
            )
        });
    });
    group.finish();
}

fn bench_parse_no_crc_no_body(c: &mut Criterion) {
    // Throughput not included in this benchmark as it is a bit confusing what the number reporting
    // represents. If parsing the header reports based on the entire size of the replay, it will be
    // some very large number (20 GB/s), else it may look deceptively small
    let data = include_bytes!("../assets/replays/good/3381.replay");
    let mut group = c.benchmark_group("parse_no_crc_no_body");
    group.bench_function("bench_parse_no_crc_no_body", |b| {
        b.iter(|| {
            black_box(
                ParserBuilder::new(data)
                    .on_error_check_crc()
                    .never_parse_network_data()
                    .parse()
                    .unwrap(),
            )
        });
    });
    group.finish();
}

fn bench_parse_crc_json(c: &mut Criterion) {
    let data = include_bytes!("../assets/replays/good/3381.replay");
    let mut group = c.benchmark_group("parse_crc_json");
    group.throughput(Throughput::Bytes(data.len() as u64));
    group.sample_size(10);
    group.bench_function("bench_parse_crc_json", |b| {
        // allocate a buffer big enough to hold all of the serialized data
        let mut bytes = Vec::with_capacity(2_usize.pow(25));
        b.iter(|| {
            let data = ParserBuilder::new(data).always_check_crc().parse().unwrap();
            black_box(serde_json::to_writer(&mut bytes, &data).unwrap());
            unsafe {
                bytes.set_len(0);
            }
        });
    });
    group.finish();
}

criterion_group!(
    benches,
    bench_crc,
    bench_json_serialization,
    bench_parse_crc_body,
    bench_parse_no_crc_body,
    bench_parse_no_crc_no_body,
    bench_parse_crc_json,
);

criterion_main!(benches);
<|endoftext|>