Skip to main content

ferrijs_std/stream_web/utils/
queue.rs

1use std::collections::VecDeque;
2
3use rquickjs::{class::Trace, Ctx, Exception, JsLifetime, Result, Value};
4
5use crate::stream_web::queuing_strategy::SizeValue;
6
7/// QueueWithSize is present in readable and writable streams and abstracts away certain queue operations
8/// https://streams.spec.whatwg.org/#queue-with-sizes
9#[derive(JsLifetime, Trace, Default)]
10pub struct QueueWithSizes<'js> {
11    pub queue: VecDeque<ValueWithSize<'js>>,
12    pub queue_total_size: f64,
13}
14
15impl<'js> QueueWithSizes<'js> {
16    pub fn new() -> Self {
17        Self {
18            queue: VecDeque::new(),
19            queue_total_size: 0.0,
20        }
21    }
22
23    pub(crate) fn enqueue_value_with_size(
24        &mut self,
25        ctx: &Ctx<'js>,
26        value: Value<'js>,
27        size: SizeValue<'js>,
28    ) -> Result<()> {
29        let size = match is_non_negative_number(size) {
30            None => {
31                // If ! IsNonNegativeNumber(size) is false, throw a RangeError exception.
32                return Err(Exception::throw_range(
33                    ctx,
34                    "Size must be a finite, non-NaN, non-negative number.",
35                ));
36            },
37            Some(size) => size,
38        };
39
40        // If size is +∞, throw a RangeError exception.
41        if size.is_infinite() {
42            return Err(Exception::throw_range(
43                ctx,
44                "Size must be a finite, non-NaN, non-negative number.",
45            ));
46        };
47
48        // Append a new value-with-size with value value and size size to container.[[queue]].
49        self.queue.push_back(ValueWithSize { value, size });
50
51        // Set container.[[queueTotalSize]] to container.[[queueTotalSize]] + size.
52        self.queue_total_size += size;
53
54        Ok(())
55    }
56
57    pub fn dequeue_value(&mut self) -> Value<'js> {
58        // Let valueWithSize be container.[[queue]][0].
59        // Remove valueWithSize from container.[[queue]].
60        let value_with_size = self
61            .queue
62            .pop_front()
63            .expect("DequeueValue called with empty queue");
64        // Set container.[[queueTotalSize]] to container.[[queueTotalSize]] − valueWithSize’s size.
65        self.queue_total_size -= value_with_size.size;
66        // If container.[[queueTotalSize]] < 0, set container.[[queueTotalSize]] to 0. (This can occur due to rounding errors.)
67        if self.queue_total_size < 0.0 {
68            self.queue_total_size = 0.0
69        }
70        value_with_size.value
71    }
72
73    pub fn reset_queue(&mut self) {
74        // Set container.[[queue]] to a new empty list.
75        self.queue.clear();
76        // Set container.[[queueTotalSize]] to 0.
77        self.queue_total_size = 0.0;
78    }
79}
80
81#[derive(JsLifetime, Trace, Clone)]
82pub struct ValueWithSize<'js> {
83    pub value: Value<'js>,
84    size: f64,
85}
86
87fn is_non_negative_number(value: SizeValue<'_>) -> Option<f64> {
88    // If Type(v) is not Number, return false.
89    let number = value.as_number()?;
90    // If v is NaN, return false.
91    if number.is_nan() {
92        return None;
93    }
94
95    // If v < 0, return false.
96    if number < 0.0 {
97        return None;
98    }
99
100    // Return true.
101    Some(number)
102}