const std = @import("std");

const mpsc = @import("../mpsc.zig");

pub fn Queue(comptime T: type) type {
    return struct {
        const Self = @This();

        ring_buffer: mpsc.RingBuffer(T),

        pub fn init(buffer: []mpsc.Slot(T)) !Self {
            return .{
                .ring_buffer = try mpsc.RingBuffer(T).init(buffer),
            };
        }

        pub fn capacity(self: *Self) usize {
            return self.ring_buffer.capacity;
        }

        pub fn tryEnqueue(self: *Self, value: T) !void {
            try self.ring_buffer.enqueue(value);
        }

        pub fn enqueue(self: *Self, value: T) void {
            while (true) {
                self.ring_buffer.enqueue(value) catch |err| switch (err) {
                    error.Overflow => {
                        std.atomic.spinLoopHint();
                        continue;
                    },
                };
                return;
            }
        }

        pub fn tryDequeue(self: *Self) !T {
            return try self.ring_buffer.dequeue();
        }

        pub fn dequeue(self: *Self) ?T {
            return self.ring_buffer.dequeue() catch |err| switch (err) {
                error.Underflow => return null,
            };
        }

        pub fn tryDequeueAll(self: *Self, buf: []T) ![]T {
            return try self.ring_buffer.dequeueAll(buf);
        }
    };
}
