What is the difference between crossbeam_queue::ArrayQueue and SegQueue for concurrent queue implementations?

crossbeam_queue::ArrayQueue is a bounded MPMC queue backed by a fixed-size array, while SegQueue is an unbounded MPMC queue built from linked segmentsβ€”ArrayQueue has a compile-time capacity with potential for push/pop failure when full/empty, whereas SegQueue grows dynamically but has higher per-operation overhead. The choice between them depends on whether you need fixed memory bounds with deterministic behavior or dynamic growth with unbounded capacity.

Understanding Concurrent Queue Requirements

use crossbeam_queue::ArrayQueue;
use crossbeam_queue::SegQueue;
 
fn concurrent_queue_basics() {
    // Both ArrayQueue and SegQueue are Multi-Producer Multi-Consumer (MPMC) queues
    // Multiple threads can push and pop concurrently
    
    // ArrayQueue: Bounded, fixed capacity
    let array_queue: ArrayQueue<i32> = ArrayQueue::new(100);
    
    // SegQueue: Unbounded, grows as needed
    let seg_queue: SegQueue<i32> = SegQueue::new();
    
    // Both support push and pop operations from multiple threads
    // Both are lock-free (no mutexes or condition variables)
    // Both are efficient for concurrent access
}

Both queues provide thread-safe MPMC semantics but differ fundamentally in their memory model.

ArrayQueue: Bounded Fixed-Capacity Queue

use crossbeam_queue::ArrayQueue;
use std::thread;
 
fn array_queue_characteristics() {
    // ArrayQueue has a fixed capacity determined at creation
    
    let queue: ArrayQueue<String> = ArrayQueue::new(3);  // Capacity of 3
    
    // Successful pushes
    assert!(queue.push("first".to_string()).is_ok());
    assert!(queue.push("second".to_string()).is_ok());
    assert!(queue.push("third".to_string()).is_ok());
    
    // Queue is full - push fails
    assert!(queue.push("fourth".to_string()).is_err());
    
    // Pop succeeds
    assert_eq!(queue.pop(), Ok("first".to_string()));
    
    // Now there's room for another push
    assert!(queue.push("fourth".to_string()).is_ok());
    
    // Empty all elements
    queue.pop().unwrap();
    queue.pop().unwrap();
    queue.pop().unwrap();
    
    // Queue is empty - pop fails
    assert!(queue.pop().is_err());
}

ArrayQueue has a fixed capacity; operations fail when full or empty.

SegQueue: Unbounded Dynamic Queue

use crossbeam_queue::SegQueue;
 
fn seg_queue_characteristics() {
    // SegQueue grows dynamically - no capacity limit
    
    let queue: SegQueue<String> = SegQueue::new();
    
    // Push never fails - queue grows as needed
    for i in 0..1000 {
        queue.push(format!("item_{}", i));
    }
    
    // All 1000 items are stored
    assert_eq!(queue.len(), 1000);
    
    // Pop items
    for i in 0..1000 {
        assert_eq!(queue.pop(), Some(format!("item_{}", i)));
    }
    
    // When empty, pop returns None (not an error)
    assert!(queue.pop().is_none());
}

SegQueue grows unboundedly; push always succeeds but memory is unbounded.

Type Signatures and Return Values

use crossbeam_queue::{ArrayQueue, SegQueue};
 
fn return_types() {
    // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    // β”‚ Method       β”‚ ArrayQueue                β”‚ SegQueue                  β”‚
    // β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    // β”‚ push(T)      β”‚ Result<(), T>             β”‚ ()                        β”‚
    // β”‚ pop()        β”‚ Result<T, PopError>       β”‚ Option<T>                 β”‚
    // β”‚ capacity     β”‚ usize (fixed)             β”‚ None                      β”‚
    // β”‚ len()        β”‚ usize (approximate)       β”‚ usize (approximate)       β”‚
    // β”‚ is_empty()   β”‚ bool                      β”‚ bool                      β”‚
    // β”‚ is_full()    β”‚ bool                      β”‚ N/A (always false)        β”‚
    // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    
    let array: ArrayQueue<i32> = ArrayQueue::new(5);
    let seg: SegQueue<i32> = SegQueue::new();
    
    // ArrayQueue::push returns Result - can fail when full
    match array.push(1) {
        Ok(()) => println!("Pushed successfully"),
        Err(item) => println!("Queue full, item returned: {}", item),
    }
    
    // SegQueue::push returns () - always succeeds
    seg.push(1);  // Just () - no failure possible
    
    // ArrayQueue::pop returns Result
    match array.pop() {
        Ok(item) => println!("Got: {}", item),
        Err(_) => println!("Queue empty"),
    }
    
    // SegQueue::pop returns Option
    match seg.pop() {
        Some(item) => println!("Got: {}", item),
        None => println!("Queue empty"),
    }
}

ArrayQueue returns Result for fallible operations; SegQueue returns Option and ().

Memory Layout and Allocation

use crossbeam_queue::{ArrayQueue, SegQueue};
 
fn memory_layout() {
    // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    // β”‚ Aspect          β”‚ ArrayQueue            β”‚ SegQueue                    β”‚
    // β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    // β”‚ Allocation      β”‚ Single contiguous     β”‚ Segments (linked)           β”‚
    // β”‚ Capacity        β”‚ Fixed at creation     β”‚ Grows dynamically           β”‚
    // β”‚ Memory bounds   β”‚ Strict upper bound    β”‚ Unbounded                   β”‚
    // β”‚ Per-element     β”‚ No extra allocation   β”‚ Some segment overhead       β”‚
    // β”‚ Cache behavior   β”‚ Better locality       β”‚ Pointer chasing            β”‚
    // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    
    // ArrayQueue: Pre-allocated contiguous memory
    // - Fixed size: sizeof(ArrayQueue<T>) β‰ˆ sizeof(capacity * T) + metadata
    // - No allocations during operation
    // - Better cache locality
    
    let array: ArrayQueue<[u8; 1024]> = ArrayQueue::new(100);
    // Memory: ~100KB allocated upfront for 100 items
    
    // SegQueue: Linked segments
    // - Grows as needed: each segment holds multiple items
    // - Allocations occur during push operations
    // - Segments are linked (pointer chasing)
    
    let seg: SegQueue<[u8; 1024]> = SegQueue::new();
    // Initially: small allocation
    // As items added: segments allocated and linked
}

ArrayQueue uses pre-allocated contiguous memory; SegQueue uses linked segments.

Performance Characteristics

use crossbeam_queue::{ArrayQueue, SegQueue};
use std::time::Instant;
 
fn performance_comparison() {
    // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    // β”‚ Scenario           β”‚ ArrayQueue            β”‚ SegQueue                  β”‚
    // β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    // β”‚ Contention low     β”‚ Very fast            β”‚ Fast                      β”‚
    // β”‚ Contention high    β”‚ Fast with backoff    β”‚ Good scalability           β”‚
    // β”‚ Memory overhead    β”‚ Fixed, predictable    β”‚ Variable, grows           β”‚
    // β”‚ Push when full     β”‚ Fails immediately    β”‚ Never fails               β”‚
    // β”‚ Pop when empty     β”‚ Fails immediately    β”‚ Returns None              β”‚
    // β”‚ Cache locality     β”‚ Excellent            β”‚ Good within segments      β”‚
    // β”‚ Memory fragmentationβ”‚ None               β”‚ Some segment allocation    β”‚
    // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    
    // ArrayQueue is typically faster when:
    // 1. You can predict maximum size
    // 2. You want bounded memory
    // 3. You need predictable allocation behavior
    
    // SegQueue is better when:
    // 1. Size is unpredictable
    // 2. Memory bounds aren't critical
    // 3. Simpler API (no capacity management)
}

ArrayQueue has better cache locality and fixed overhead; SegQueue scales better for unbounded cases.

Thread Safety and Concurrency

use crossbeam_queue::{ArrayQueue, SegQueue};
use std::thread;
use std::sync::Arc;
 
fn thread_safety() {
    // Both are fully thread-safe MPMC queues
    
    // ArrayQueue in multi-threaded context
    let array_queue = Arc::new(ArrayQueue::new(1000));
    let mut handles = vec![];
    
    // Multiple producers
    for i in 0..10 {
        let q = Arc::clone(&array_queue);
        handles.push(thread::spawn(move || {
            for j in 0..100 {
                // May fail if queue is full
                while q.push(i * 100 + j).is_err() {
                    // Spin or wait
                }
            }
        }));
    }
    
    // Multiple consumers
    for _ in 0..5 {
        let q = Arc::clone(&array_queue);
        handles.push(thread::spawn(move || {
            let mut count = 0;
            while count < 200 {
                if q.pop().is_ok() {
                    count += 1;
                }
            }
        }));
    }
    
    handles.into_iter().for_each(|h| h.join().unwrap());
}

Both queues support concurrent access from multiple threads without additional synchronization.

Handling Backpressure with ArrayQueue

use crossbeam_queue::ArrayQueue;
use std::thread;
use std::sync::Arc;
use std::time::Duration;
 
fn backpressure_handling() {
    // ArrayQueue enables backpressure - when full, producers must wait
    
    let queue = Arc::new(ArrayQueue::new(10));
    
    // Producer thread
    let producer_queue = Arc::clone(&queue);
    let producer = thread::spawn(move || {
        for i in 0..100 {
            // Try to push, with retry on full
            loop {
                match producer_queue.push(i) {
                    Ok(()) => break,
                    Err(item) => {
                        // Queue is full - apply backpressure
                        println!("Queue full, retrying item {}", item);
                        thread::yield_now();
                    }
                }
            }
        }
    });
    
    // Consumer thread
    let consumer_queue = Arc::clone(&queue);
    let consumer = thread::spawn(move || {
        thread::sleep(Duration::from_millis(10));
        while let Ok(item) = consumer_queue.pop() {
            println!("Consumed: {}", item);
        }
    });
    
    // Backpressure naturally slows producer when queue fills
    // This prevents unbounded memory growth
}

ArrayQueue provides natural backpressure; full queues force producers to wait.

Unbounded Growth Risk with SegQueue

use crossbeam_queue::SegQueue;
use std::thread;
use std::sync::Arc;
 
fn unbounded_risk() {
    // SegQueue can grow unboundedly - potential memory exhaustion
    
    let queue = Arc::new(SegQueue::new());
    
    // Fast producer, slow consumer
    let producer_queue = Arc::clone(&queue);
    let producer = thread::spawn(move || {
        for i in 0..1_000_000 {
            // This NEVER blocks - queue grows indefinitely
            producer_queue.push(i);
        }
    });
    
    let consumer_queue = Arc::clone(&queue);
    let consumer = thread::spawn(move || {
        thread::sleep(std::time::Duration::from_secs(1));
        // Consumer is slow - queue has grown huge
        while consumer_queue.pop().is_some() {
            // Process items
        }
    });
    
    // Risk: If consumer can't keep up, memory grows unbounded
    // In production: need external mechanism to limit production
    
    producer.join().unwrap();
    consumer.join().unwrap();
}

SegQueue requires external mechanisms to prevent unbounded memory growth.

Capacity Management

use crossbeam_queue::ArrayQueue;
 
fn capacity_management() {
    // ArrayQueue: Capacity is part of type semantics
    
    let queue: ArrayQueue<String> = ArrayQueue::new(100);
    
    // Know the capacity
    assert_eq!(queue.capacity(), 100);
    
    // Check if full before pushing
    if !queue.is_full() {
        queue.push("item".to_string()).unwrap();
    }
    
    // Check current size (approximate)
    println!("Queue size: {}", queue.len());
    
    // You can proactively manage the queue
    // If queue.is_full(), apply backpressure or allocate resources
}
 
// SegQueue has no capacity concept - it always grows
fn seg_queue_no_capacity() {
    use crossbeam_queue::SegQueue;
    
    let queue: SegQueue<String> = SegQueue::new();
    
    // No capacity() method
    // No is_full() method
    // Only len() for approximate size
    
    println!("Queue size: {}", queue.len());
    
    // You cannot proactively prevent growth
    // External mechanisms needed for memory management
}

ArrayQueue exposes capacity for proactive management; SegQueue has no such concept.

Choosing Between ArrayQueue and SegQueue

use crossbeam_queue::{ArrayQueue, SegQueue};
 
fn choosing_queue() {
    // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    // β”‚ Use ArrayQueue when:                                                    β”‚
    // β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    // β”‚ β€’ Maximum size is known or bounded                                    β”‚
    // β”‚ β€’ Memory must have strict upper bound                                 β”‚
    // β”‚ β€’ Backpressure is desired (producers slow when full)                  β”‚
    // β”‚ β€’ Predictable memory behavior is required                             β”‚
    // β”‚ β€’ Better cache locality matters                                        β”‚
    // β”‚ β€’ Low-latency push/pop is critical                                     β”‚
    // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    
    // Example: Thread pool task queue with bounded size
    let task_queue: ArrayQueue<Box<dyn FnOnce()>> = ArrayQueue::new(1000);
    
    // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    // β”‚ Use SegQueue when:                                                     β”‚
    // β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    // β”‚ β€’ Size is unpredictable                                               β”‚
    // β”‚ β€’ Memory bounds aren't critical                                       β”‚
    // β”‚ β€’ Simpler API is preferred (no capacity errors)                       β”‚
    // β”‚ β€’ Producers should never block                                        β”‚
    // β”‚ β€’ Bursty workloads with temporary spikes                              β”‚
    // β”‚ β€’ External mechanisms control memory                                   β”‚
    // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    
    // Example: Event channel where events should never be dropped
    let event_queue: SegQueue<Event> = SegQueue::new();
}
 
struct Event { event_type: String }

Choose based on memory constraints, predictability needs, and backpressure requirements.

Real-World Use Cases

use crossbeam_queue::{ArrayQueue, SegQueue};
use std::sync::Arc;
 
fn real_world_examples() {
    // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    // β”‚ Use Case                    β”‚ Recommended Queue                        β”‚
    // β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    // β”‚ Thread pool task queue     β”‚ ArrayQueue (bounded, backpressure)       β”‚
    // β”‚ Network packet buffer      β”‚ ArrayQueue (bounded, drop on full)       β”‚
    // β”‚ Event broadcast            β”‚ SegQueue (unbounded, no drop)            β”‚
    // β”‚ Log message queue          β”‚ SegQueue (bursty, unbounded)             β”‚
    // β”‚ Actor mailbox              β”‚ Depends on actor semantics               β”‚
    // β”‚ Job queue (batch)          β”‚ ArrayQueue (bounded, fair scheduling)    β”‚
    // β”‚ Message passing            β”‚ Depends on protocol guarantees          β”‚
    // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    
    // Thread pool with bounded work queue
    struct ThreadPool {
        tasks: Arc<ArrayQueue<Box<dyn FnOnce() + Send>>>,
        workers: Vec<thread::JoinHandle<()>>,
    }
    
    // Event system where events must not be lost
    struct EventBus {
        events: SegQueue<Event>,
    }
    
    // bounded queue with overflow handling
    struct BoundedChannel<T> {
        queue: ArrayQueue<T>,
        overflow_policy: OverflowPolicy,
    }
    
    enum OverflowPolicy {
        DropNewest,
        DropOldest,
        Block,
    }
}

Different use cases favor different queue implementations based on their requirements.

Complete Summary

use crossbeam_queue::{ArrayQueue, SegQueue};
 
fn complete_summary() {
    // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    // β”‚ Characteristic    β”‚ ArrayQueue           β”‚ SegQueue                   β”‚
    // β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    // β”‚ Capacity          β”‚ Bounded (fixed)      β”‚ Unbounded (grows)          β”‚
    // β”‚ Allocation        β”‚ Upfront              β”‚ On demand                  β”‚
    // β”‚ Memory            β”‚ Contiguous array     β”‚ Linked segments            β”‚
    // β”‚ push(T) return    β”‚ Result<(), T>        β”‚ ()                         β”‚
    // β”‚ pop() return      β”‚ Result<T, PopError>  β”‚ Option<T>                  β”‚
    // β”‚ Failure mode      β”‚ Returns error        β”‚ Never fails                β”‚
    // β”‚ Backpressure      β”‚ Built-in             β”‚ None                       β”‚
    // β”‚ Cache locality    β”‚ Excellent            β”‚ Good                       β”‚
    // β”‚ Memory bounds     β”‚ Strict               β”‚ None                       β”‚
    // β”‚ Complexity        β”‚ O(1) all operations  β”‚ O(1) amortized             β”‚
    // β”‚ Use when          β”‚ Known capacity       β”‚ Unknown capacity           β”‚
    // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    
    // Key differences:
    
    // 1. Capacity management
    // ArrayQueue: You choose capacity at creation; it never grows
    // SegQueue: Starts small, grows as needed, never reports full
    
    // 2. Error handling
    // ArrayQueue: push/pop return Result - you handle full/empty
    // SegQueue: push always succeeds; pop returns Option
    
    // 3. Memory behavior
    // ArrayQueue: Predictable memory footprint
    // SegQueue: Memory grows with queue size (potential exhaustion)
    
    // 4. Backpressure
    // ArrayQueue: Full queue provides natural backpressure
    // SegQueue: No backpressure - producers run unbounded
    
    // Choose ArrayQueue for bounded, predictable systems
    // Choose SegQueue for simpler unbounded use cases
}
 
// Key insight:
// ArrayQueue and SegQueue serve different design constraints.
// ArrayQueue provides a bounded queue with strict memory limits and
// backpressure - when full, producers must wait. This is ideal for
// systems where you need to prevent unbounded memory growth.
//
// SegQueue provides an unbounded queue that grows dynamically -
// simpler API (no capacity management) but requires external
// mechanisms to prevent memory exhaustion. Use when you need to
// handle bursty workloads and can tolerate memory growth, or when
// dropping items is unacceptable.
//
// The push/pop return types reflect their nature:
// ArrayQueue::push returns Result because it can fail (full)
// SegQueue::push returns () because it never fails
// ArrayQueue::pop returns Result because empty is an error state
// SegQueue::pop returns Option because empty is normal (None)

Key insight: ArrayQueue is a bounded queue with fixed capacity and Result-based operations that can fail, providing natural backpressure when full. SegQueue is an unbounded queue that grows dynamically with infallible push and Option-based pop, but requires external mechanisms to prevent memory exhaustion. Choose ArrayQueue for bounded, predictable systems with backpressure; choose SegQueue for simpler unbounded use cases where memory growth is acceptable or externally managed.