script/dom/encoding/
textencoder.rs1use std::ptr;
6
7use dom_struct::dom_struct;
8use js::gc::CustomAutoRooterGuard;
9use js::jsapi::JSObject;
10use js::rust::HandleObject;
11use js::typedarray;
12use js::typedarray::HeapUint8Array;
13use script_bindings::trace::RootedTraceableBox;
14
15use crate::dom::bindings::buffer_source::create_buffer_source;
16use crate::dom::bindings::codegen::Bindings::TextEncoderBinding::{
17 TextEncoderEncodeIntoResult, TextEncoderMethods,
18};
19use crate::dom::bindings::error::Fallible;
20use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
21use crate::dom::bindings::root::DomRoot;
22use crate::dom::bindings::str::{DOMString, USVString};
23use crate::dom::globalscope::GlobalScope;
24use crate::script_runtime::{CanGc, JSContext};
25
26#[dom_struct]
28pub(crate) struct TextEncoder {
29 reflector_: Reflector,
30}
31
32impl TextEncoder {
33 fn new_inherited() -> TextEncoder {
34 TextEncoder {
35 reflector_: Reflector::new(),
36 }
37 }
38
39 fn new(
40 global: &GlobalScope,
41 proto: Option<HandleObject>,
42 can_gc: CanGc,
43 ) -> DomRoot<TextEncoder> {
44 reflect_dom_object_with_proto(
45 Box::new(TextEncoder::new_inherited()),
46 global,
47 proto,
48 can_gc,
49 )
50 }
51}
52
53impl TextEncoderMethods<crate::DomTypeHolder> for TextEncoder {
54 fn Constructor(
56 global: &GlobalScope,
57 proto: Option<HandleObject>,
58 can_gc: CanGc,
59 ) -> Fallible<DomRoot<TextEncoder>> {
60 Ok(TextEncoder::new(global, proto, can_gc))
61 }
62
63 fn Encoding(&self) -> DOMString {
65 DOMString::from("utf-8")
66 }
67
68 fn Encode(
70 &self,
71 cx: JSContext,
72 input: USVString,
73 can_gc: CanGc,
74 ) -> RootedTraceableBox<HeapUint8Array> {
75 let encoded = input.0.as_bytes();
76
77 rooted!(in(*cx) let mut js_object = ptr::null_mut::<JSObject>());
78 create_buffer_source(cx, encoded, js_object.handle_mut(), can_gc)
79 .expect("Converting input to uint8 array should never fail")
80 }
81
82 #[expect(unsafe_code)]
84 fn EncodeInto(
85 &self,
86 source: USVString,
87 mut destination: CustomAutoRooterGuard<typedarray::Uint8Array>,
88 ) -> TextEncoderEncodeIntoResult {
89 let available = destination.len();
90
91 if available == 0 {
93 return TextEncoderEncodeIntoResult {
94 read: Some(0),
95 written: Some(0),
96 };
97 }
98
99 let mut read = 0;
100 let mut written = 0;
101
102 let dest = unsafe { destination.as_mut_slice() };
103
104 for result in source.0.chars() {
108 let utf8_len = result.len_utf8();
109 if available - written >= utf8_len {
110 read += if result > '\u{FFFF}' { 2 } else { 1 };
113
114 let target = &mut dest[written..written + utf8_len];
116 result.encode_utf8(target);
117
118 written += utf8_len;
120 } else {
121 break;
124 }
125 }
126
127 TextEncoderEncodeIntoResult {
128 read: Some(read),
129 written: Some(written as _),
130 }
131 }
132}