script/dom/
countqueuingstrategy.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::rc::Rc;

use dom_struct::dom_struct;
use js::jsapi::{CallArgs, JSContext};
use js::jsval::{Int32Value, JSVal};
use js::rust::HandleObject;

use super::bindings::codegen::Bindings::FunctionBinding::Function;
use super::bindings::codegen::Bindings::QueuingStrategyBinding::{
    CountQueuingStrategyMethods, QueuingStrategy, QueuingStrategyInit, QueuingStrategySize,
};
use super::bindings::error::{Error, Fallible};
use super::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
use super::bindings::root::DomRoot;
use super::types::GlobalScope;
use crate::script_runtime::CanGc;
use crate::{native_fn, native_raw_obj_fn};

#[dom_struct]
pub(crate) struct CountQueuingStrategy {
    reflector_: Reflector,
    high_water_mark: f64,
}

impl CountQueuingStrategy {
    pub(crate) fn new_inherited(init: f64) -> Self {
        Self {
            reflector_: Reflector::new(),
            high_water_mark: init,
        }
    }

    pub(crate) fn new(
        global: &GlobalScope,
        proto: Option<HandleObject>,
        init: f64,
        can_gc: CanGc,
    ) -> DomRoot<Self> {
        reflect_dom_object_with_proto(Box::new(Self::new_inherited(init)), global, proto, can_gc)
    }
}

impl CountQueuingStrategyMethods<crate::DomTypeHolder> for CountQueuingStrategy {
    /// <https://streams.spec.whatwg.org/#cqs-constructor>
    fn Constructor(
        global: &GlobalScope,
        proto: Option<HandleObject>,
        can_gc: CanGc,
        init: &QueuingStrategyInit,
    ) -> DomRoot<Self> {
        Self::new(global, proto, init.highWaterMark, can_gc)
    }

    /// <https://streams.spec.whatwg.org/#cqs-high-water-mark>
    fn HighWaterMark(&self) -> f64 {
        self.high_water_mark
    }

    /// <https://streams.spec.whatwg.org/#cqs-size>
    fn GetSize(&self, _can_gc: CanGc) -> Fallible<Rc<Function>> {
        let global = self.global();
        // Return this's relevant global object's count queuing strategy
        // size function.
        if let Some(fun) = global.get_count_queuing_strategy_size() {
            return Ok(fun);
        }

        // Step 1. Let steps be the following steps, given chunk
        // Note: See ByteLengthQueuingStrategySize instead.

        // Step 2. Let F be !CreateBuiltinFunction(steps, 1, "size", « »,
        // globalObject’s relevant Realm).
        let fun = native_fn!(count_queuing_strategy_size, c"size", 0, 0);
        // Step 3. Set globalObject’s count queuing strategy size function to
        // a Function that represents a reference to F,
        // with callback context equal to globalObject’s relevant settings object.
        global.set_count_queuing_strategy_size(fun.clone());
        Ok(fun)
    }
}

/// <https://streams.spec.whatwg.org/#count-queuing-strategy-size-function>
#[allow(unsafe_code)]
pub(crate) unsafe fn count_queuing_strategy_size(
    _cx: *mut JSContext,
    argc: u32,
    vp: *mut JSVal,
) -> bool {
    let args = CallArgs::from_vp(vp, argc);
    // Step 1.1. Return 1.
    args.rval().set(Int32Value(1));
    true
}

/// Extract the high water mark from a QueuingStrategy.
/// If the high water mark is not set, return the default value.
///
/// <https://streams.spec.whatwg.org/#validate-and-normalize-high-water-mark>
pub(crate) fn extract_high_water_mark(
    strategy: &QueuingStrategy,
    default_hwm: f64,
) -> Result<f64, Error> {
    if strategy.highWaterMark.is_none() {
        return Ok(default_hwm);
    }

    let high_water_mark = strategy.highWaterMark.unwrap();
    if high_water_mark.is_nan() || high_water_mark < 0.0 {
        return Err(Error::Range(
            "High water mark must be a non-negative number.".to_string(),
        ));
    }

    Ok(high_water_mark)
}

/// Extract the size algorithm from a QueuingStrategy.
/// If the size algorithm is not set, return a fallback function which always returns 1.
///
/// <https://streams.spec.whatwg.org/#make-size-algorithm-from-size-function>
pub(crate) fn extract_size_algorithm(
    strategy: &QueuingStrategy,
    _can_gc: CanGc,
) -> Rc<QueuingStrategySize> {
    if strategy.size.is_none() {
        let cx = GlobalScope::get_cx();
        let fun_obj = native_raw_obj_fn!(cx, count_queuing_strategy_size, c"size", 0, 0);
        #[allow(unsafe_code)]
        unsafe {
            return QueuingStrategySize::new(cx, fun_obj);
        };
    }
    strategy.size.as_ref().unwrap().clone()
}