Skip to main content

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