simple_ringbuf 0.1.2

Simple Ringbuf is a speedy lightweight fixed-size infinite-use collection optimized for straightforward single threaded use.
Documentation
//! Contains implementations for raw, unsafe backing types
//! for the ring buffer implementation. `RawVec` in the
//! [Rustonomicon](https://doc.rust-lang.org/nomicon/vec.html) is
//! the reference type for this implementation. At the time of writing
//! (6/12/2019) the Rustonomicon entry is somewhat out of date with the
//! current state of Rust.
//!
//! The primary departures are to make this work on stable, and update
//! a few outdated types.
//! We Use the stabilized `NonNull` in place of
//! `Unique`, and do not use the nightly `GlobalAllocator`
//! preferring the currently stable `alloc` and `dealloc`.
//!
//! Additionally, a few unstable methods on `Layout` are hand-copied
//! for convenience.

use std::alloc::{alloc, dealloc, handle_alloc_error, realloc, Layout};
use std::mem;
use std::ptr::NonNull;

/// A raw fixed-size non-growable buffer. This properly handles ZSTs
/// and Null Pointer Optimizations. NOTE: The cap is the size of the
/// internal buffer, the actual ring buffer structure should not rely on this
/// for ZSTs.
pub(crate) struct RawRingBuffer<T> {
    pub ptr: NonNull<T>,
    pub cap: usize,
}

impl<T> RawRingBuffer<T> {
    /// Creates a new fixed-size buffer, with special casing for ZSTs.
    /// Note, for ZSTs the capacity will be ignored and set to !0.
    pub fn new(cap: usize) -> Self {
        assert_ne!(cap, 0, "RingBuffer's capacity must be a non-zero value");

        if mem::size_of::<T>() == 0 {
            return RawRingBuffer {
                ptr: NonNull::dangling(),
                cap: !0,
            };
        }

        unsafe {
            let elem_size = mem::size_of::<T>();

            let ptr = alloc(array_layout::<T>(cap).unwrap());

            if ptr.is_null() {
                handle_alloc_error(Layout::from_size_align_unchecked(
                    cap * elem_size,
                    mem::align_of::<T>(),
                ))
            }

            RawRingBuffer {
                ptr: NonNull::new_unchecked(ptr as *mut _),
                cap,
            }
        }
    }

    pub fn resize(&mut self, new_cap: usize) {
        if mem::size_of::<T>() == 0 {
            return;
        }

        unsafe {
            let new_ptr = realloc(
                self.ptr.as_ptr() as *mut _,
                array_layout::<T>(self.cap).unwrap(),
                array_layout::<T>(new_cap).unwrap().size(),
            );

            if new_ptr.is_null() {
                handle_alloc_error(Layout::from_size_align_unchecked(
                    new_cap * mem::size_of::<T>(),
                    mem::align_of::<T>(),
                ))
            }

            self.cap = new_cap;
            self.ptr = NonNull::new_unchecked(new_ptr as *mut _);
        }
    }
}

impl<T> Drop for RawRingBuffer<T> {
    fn drop(&mut self) {
        let elem_size = mem::size_of::<T>();
        if self.cap != 0 && elem_size != 0 {
            unsafe {
                dealloc(
                    self.ptr.as_ptr() as *mut _,
                    array_layout::<T>(self.cap).unwrap(),
                )
            }
        }
    }
}

/* The following methods are lifted from the currently unstable source for Layout
*  (as of Rust 1.35 stable). Due to using portions of the Rust codebase we must reprint the MIT
*  License it uses.
*/

//Permission is hereby granted, free of charge, to any
//person obtaining a copy of this software and associated
//documentation files (the "Software"), to deal in the
//Software without restriction, including without
//limitation the rights to use, copy, modify, merge,
//publish, distribute, sublicense, and/or sell copies of
//the Software, and to permit persons to whom the Software
//is furnished to do so, subject to the following
//conditions:
//
//The above copyright notice and this permission notice
//shall be included in all copies or substantial portions
//of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
//ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
//TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
//PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
//SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
//CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
//OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
//IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//DEALINGS IN THE SOFTWARE.

fn padding_needed_for(layout: &Layout, align: usize) -> usize {
    let len = layout.size();

    let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
    len_rounded_up.wrapping_sub(len)
}

fn layout_repeat(layout: Layout, n: usize) -> Result<(Layout, usize), ()> {
    let padded_size = layout
        .size()
        .checked_add(padding_needed_for(&layout, layout.align()))
        .ok_or(())?;

    let alloc_size = padded_size.checked_mul(n).ok_or(())?;

    unsafe {
        Ok((
            Layout::from_size_align_unchecked(alloc_size, layout.align()),
            padded_size,
        ))
    }
}

fn array_layout<T>(n: usize) -> Result<Layout, ()> {
    layout_repeat(Layout::new::<T>(), n).map(|(k, offs)| {
        debug_assert!(offs == mem::size_of::<T>());
        k
    })
}