use core::num::NonZeroUsize;
use core::{cmp::min, fmt::Debug};
use alloc::vec::Vec;
use std::vec;
use arbitrary::Arbitrary;
use crate::queues::{Queue, QueueExt};
#[derive(Debug, Clone, Copy, Arbitrary)]
pub enum QueueOp {
Enqueue,
Dequeue,
BulkEnqueue(NonZeroUsize),
BulkDequeue(NonZeroUsize),
}
pub async fn assert_fifo_queue<Q>(q: &mut Q, data: &[Q::Item], mut ops: Vec<QueueOp>)
where
Q: Queue + Debug,
Q::Item: Clone + PartialEq + Debug + Default,
{
let mut has_deq_op = false;
let mut has_enq_op = false;
for op in ops.iter() {
match op {
QueueOp::Enqueue | QueueOp::BulkEnqueue(_) => has_enq_op = true,
QueueOp::Dequeue | QueueOp::BulkDequeue(_) => has_deq_op = true,
}
}
if !has_deq_op {
ops.push(QueueOp::Dequeue);
}
if !has_enq_op {
ops.push(QueueOp::Enqueue);
}
let mut enqueued_items_count = 0;
let mut dequeued_items_count = 0;
let mut expected_current_len = 0;
let mut dequeued_items = vec![Q::Item::default(); data.len()];
let mut i = 0;
while enqueued_items_count < data.len() || dequeued_items_count < data.len() {
match ops[i] {
QueueOp::Enqueue => {
if enqueued_items_count < data.len()
&& q.enqueue(data[enqueued_items_count].clone()).is_none()
{
enqueued_items_count += 1;
expected_current_len += 1;
assert_eq!(q.len(), expected_current_len);
}
}
QueueOp::Dequeue => {
if dequeued_items_count < data.len() {
match q.dequeue() {
None => assert!(q.is_empty()),
Some(dequeued) => {
dequeued_items[dequeued_items_count] = dequeued;
dequeued_items_count += 1;
expected_current_len -= 1;
assert_eq!(q.len(), expected_current_len);
}
}
}
}
QueueOp::BulkEnqueue(amount) => {
if enqueued_items_count < data.len() {
let slice_len = min(amount.into(), data.len() - enqueued_items_count);
let amount_enqueued = q
.bulk_enqueue(&data[enqueued_items_count..enqueued_items_count + slice_len])
.await;
enqueued_items_count += amount_enqueued;
expected_current_len += amount_enqueued;
assert_eq!(q.len(), expected_current_len);
}
}
QueueOp::BulkDequeue(amount) => {
if dequeued_items_count < data.len() {
let slice_len = min(amount.into(), data.len() - dequeued_items_count);
let amount_dequeued = q
.bulk_dequeue(
&mut dequeued_items
[dequeued_items_count..dequeued_items_count + slice_len],
)
.await;
dequeued_items_count += amount_dequeued;
expected_current_len -= amount_dequeued;
assert_eq!(q.len(), expected_current_len);
}
}
}
i += 1;
if i == ops.len() {
i = 0;
}
}
assert!(q.is_empty());
assert_eq!(&dequeued_items[..], data);
}