ufotofu 0.10.1

Abstractions for lazily consuming and producing sequences
Documentation
use core::fmt;

use crate::queues::elastic::Elastic;
use crate::queues::Queue;

/// A queue whose internal storage grows and shrinks dynamically, with no upper bound.
pub struct UnboundedElastic<T> {
    inner: Elastic<T>,
}

impl<T> UnboundedElastic<T> {
    pub(crate) fn new(initialise_memory: fn() -> T) -> Self {
        Self {
            inner: Elastic::new(1, usize::MAX, initialise_memory),
        }
    }
}

impl<T> Queue for UnboundedElastic<T> {
    type Item = T;

    fn len(&self) -> usize {
        self.inner.len()
    }

    fn is_full(&self) -> bool {
        false
    }

    fn max_capacity(&self) -> Option<usize> {
        None
    }

    fn enqueue(&mut self, item: T) -> Option<T> {
        self.inner.enqueue(item)
    }

    async fn expose_slots<F, R>(&mut self, f: F) -> R
    where
        F: AsyncFnOnce(&mut [T]) -> (usize, R),
    {
        self.inner.expose_slots(f).await
    }

    fn dequeue(&mut self) -> Option<T> {
        self.inner.dequeue()
    }

    async fn expose_items<F, R>(&mut self, f: F) -> R
    where
        F: AsyncFnOnce(&[T]) -> (usize, R),
    {
        self.inner.expose_items(f).await
    }
}

impl<T: fmt::Debug> fmt::Debug for UnboundedElastic<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("UnboundedElastic")
            .field("len", &self.len())
            .field("data", &DataDebugger(self))
            .finish()
    }
}

struct DataDebugger<'q, T>(&'q UnboundedElastic<T>);

impl<T: fmt::Debug> fmt::Debug for DataDebugger<'_, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut list = f.debug_list();

        for item in self.0.inner.buffer.iter().take(self.0.len()) {
            list.entry(item);
        }

        list.finish()
    }
}

#[cfg(test)]
mod tests {
    extern crate alloc;
    use super::*;
    use crate::queues::QueueExt;
    use alloc::format;

    #[test]
    fn enqueues_and_dequeues_with_correct_amount() {
        let mut queue: UnboundedElastic<u8> = UnboundedElastic::new(Default::default);
        assert_eq!(queue.enqueue(2), None);
        assert_eq!(queue.enqueue(3), None);
        assert_eq!(queue.enqueue(5), None);
        assert_eq!(queue.enqueue(7), None);
        assert_eq!(queue.len(), 4);

        assert_eq!(queue.enqueue(11), None);
        assert_eq!(queue.len(), 5);
        assert_eq!(queue.enqueue(13), None);

        assert_eq!(queue.dequeue(), Some(2));
        assert_eq!(queue.len(), 5);

        assert_eq!(queue.enqueue(13), None);
    }

    #[test]
    fn returns_none_on_dequeue_when_queue_is_empty() {
        let mut queue: UnboundedElastic<u8> = UnboundedElastic::new(Default::default);

        queue.enqueue(2);
        queue.dequeue();

        assert!(queue.dequeue().is_none());
    }

    #[test]
    fn bulk_enqueues_and_dequeues_with_correct_amount() {
        pollster::block_on(async {
            let mut queue: UnboundedElastic<u8> = UnboundedElastic::new(Default::default);
            let mut buf = [0; 8];
            let enqueue_amount = queue.bulk_enqueue(b"ufotofu").await;
            let dequeue_amount = queue.bulk_dequeue(&mut buf).await;
            assert_eq!(enqueue_amount, dequeue_amount);
        })
    }

    #[test]
    fn test_debug_impl() {
        let mut queue: UnboundedElastic<u8> = UnboundedElastic::new(Default::default);
        assert_eq!(queue.enqueue(2), None);
        assert_eq!(queue.enqueue(3), None);
        assert_eq!(queue.enqueue(5), None);
        assert_eq!(
            format!("{queue:?}"),
            "UnboundedElastic { len: 3, data: [2, 3, 5] }"
        );

        assert_eq!(queue.dequeue(), Some(2));
        assert_eq!(
            format!("{queue:?}"),
            "UnboundedElastic { len: 2, data: [3, 5] }"
        );

        assert_eq!(queue.dequeue(), Some(3));
        assert_eq!(
            format!("{queue:?}"),
            "UnboundedElastic { len: 1, data: [5] }"
        );

        assert_eq!(queue.enqueue(7), None);
        assert_eq!(
            format!("{queue:?}"),
            "UnboundedElastic { len: 2, data: [5, 7] }"
        );

        assert_eq!(queue.enqueue(11), None);
        assert_eq!(queue.enqueue(13), None);
        assert_eq!(queue.enqueue(17), None);
        assert_eq!(
            format!("{queue:?}"),
            "UnboundedElastic { len: 5, data: [5, 7, 11, 13, 17] }"
        );
    }
}