script/dom/stream/
bytelengthqueuingstrategy.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use std::rc::Rc;
6
7use dom_struct::dom_struct;
8use js::error::throw_type_error;
9use js::gc::{HandleValue, MutableHandleValue};
10use js::jsapi::{CallArgs, JSContext};
11use js::jsval::{JSVal, UndefinedValue};
12use js::rust::HandleObject;
13
14use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
15use crate::dom::bindings::codegen::Bindings::QueuingStrategyBinding::{
16    ByteLengthQueuingStrategyMethods, QueuingStrategyInit,
17};
18use crate::dom::bindings::error::Fallible;
19use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
20use crate::dom::bindings::root::DomRoot;
21use crate::dom::bindings::utils::get_dictionary_property;
22use crate::dom::types::GlobalScope;
23use crate::native_fn;
24use crate::script_runtime::CanGc;
25
26#[dom_struct]
27pub(crate) struct ByteLengthQueuingStrategy {
28    reflector_: Reflector,
29    high_water_mark: f64,
30}
31
32impl ByteLengthQueuingStrategy {
33    pub(crate) fn new_inherited(init: f64) -> Self {
34        Self {
35            reflector_: Reflector::new(),
36            high_water_mark: init,
37        }
38    }
39
40    pub(crate) fn new(
41        global: &GlobalScope,
42        proto: Option<HandleObject>,
43        init: f64,
44        can_gc: CanGc,
45    ) -> DomRoot<Self> {
46        reflect_dom_object_with_proto(Box::new(Self::new_inherited(init)), global, proto, can_gc)
47    }
48}
49
50impl ByteLengthQueuingStrategyMethods<crate::DomTypeHolder> for ByteLengthQueuingStrategy {
51    /// <https://streams.spec.whatwg.org/#blqs-constructor>
52    fn Constructor(
53        global: &GlobalScope,
54        proto: Option<HandleObject>,
55        can_gc: CanGc,
56        init: &QueuingStrategyInit,
57    ) -> DomRoot<Self> {
58        Self::new(global, proto, init.highWaterMark, can_gc)
59    }
60    /// <https://streams.spec.whatwg.org/#blqs-high-water-mark>
61    fn HighWaterMark(&self) -> f64 {
62        self.high_water_mark
63    }
64
65    /// <https://streams.spec.whatwg.org/#blqs-size>
66    fn GetSize(&self, cx: &mut js::context::JSContext) -> Fallible<Rc<Function>> {
67        let global = self.global();
68        // Return this's relevant global object's byte length queuing strategy
69        // size function.
70        if let Some(fun) = global.get_byte_length_queuing_strategy_size() {
71            return Ok(fun);
72        }
73
74        // Step 1. Let steps be the following steps, given chunk
75        // Note: See ByteLengthQueuingStrategySize instead.
76
77        // Step 2. Let F be !CreateBuiltinFunction(steps, 1, "size", « »,
78        // globalObject’s relevant Realm).
79        let fun = native_fn!(cx, byte_length_queuing_strategy_size, c"size", 1, 0);
80        // Step 3. Set globalObject’s byte length queuing strategy size function to
81        // a Function that represents a reference to F,
82        // with callback context equal to globalObject's relevant settings object.
83        global.set_byte_length_queuing_strategy_size(fun.clone());
84        Ok(fun)
85    }
86}
87
88/// <https://streams.spec.whatwg.org/#byte-length-queuing-strategy-size-function>
89#[expect(unsafe_code)]
90pub(crate) fn byte_length_queuing_strategy_size(
91    cx: &mut js::context::JSContext,
92    args: CallArgs,
93) -> bool {
94    // Step 1. Let steps be the following steps, given chunk:
95    // Step 1.1. Return ? GetV(chunk, "byteLength").
96    let chunk = unsafe { HandleValue::from_raw(args.get(0)) };
97
98    // https://tc39.es/ecma262/#sec-getv
99    // Let O be ? ToObject(V).
100    if chunk.is_undefined() || chunk.is_null() {
101        unsafe {
102            throw_type_error(
103                cx.raw_cx(),
104                c"ByteLengthQueuingStrategy size called with undefined or nulll",
105            )
106        };
107        return false;
108    }
109
110    if !chunk.is_object() {
111        // Return ? O.[[Get]]("byteLength", V).
112        // undefined for primitives without the property.
113        args.rval().set(UndefinedValue());
114        return true;
115    }
116
117    rooted!(&in(cx) let object = chunk.to_object());
118
119    // Return ? O.[[Get]](P, V).
120    match unsafe {
121        get_dictionary_property(
122            cx.raw_cx(),
123            object.handle(),
124            c"byteLength",
125            MutableHandleValue::from_raw(args.rval()),
126            CanGc::from_cx(cx),
127        )
128    } {
129        Ok(true) => true,
130        Ok(false) => {
131            args.rval().set(UndefinedValue());
132            true
133        },
134        Err(()) => false,
135    }
136}