The crate/module name:

use crossbeam::queue::ring_buffer;;
let (p, c): (ring_buffer::Producer<i32>, ring_buffer::Consumer<i32>) =

Since module-level new() seems to be un-idiomatic, what about something like this:

use crossbeam::queue::ring_buffer;
let (p, c) = ring_buffer::split::<f32>(100);

The consumer side:

struct Consumer<T>;

impl<T> Consumer<T> {
    fn slots(&self) -> usize;

    fn as_slices(&self) -> (&[T], &[T]);
    /// `Copy` is required because the ring buffer never drops items (unless it is dropped itself).
    fn advance(&mut self, n: usize) where T: Copy;

    fn pop(&mut self) -> Result<T, PopError>;
    fn pop_batch(&mut self) -> PopBatch<'_, T>;

struct PopBatch<'a, T>;

impl<T> PopBatch<'_, T> {
    fn slots(&self) -> usize;
    fn pop(&mut self) -> Result<T, PopError>;

The producer side:

struct Producer<T>;

impl<T> Producer<T> {
    fn slots(&self) -> usize;

    fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) where T: Copy + Default;