script/dom/encoding/
textencoder.rs1use std::ptr;
6
7use dom_struct::dom_struct;
8use js::context::{JSContext, NoGC};
9use js::gc::CustomAutoRooterGuard;
10use js::jsapi::JSObject;
11use js::rust::HandleObject;
12use js::typedarray;
13use js::typedarray::HeapUint8Array;
14use script_bindings::reflector::{Reflector, reflect_dom_object_with_proto};
15use script_bindings::trace::RootedTraceableBox;
16
17use crate::dom::bindings::buffer_source::create_buffer_source;
18use crate::dom::bindings::codegen::Bindings::TextEncoderBinding::{
19 TextEncoderEncodeIntoResult, TextEncoderMethods,
20};
21use crate::dom::bindings::error::Fallible;
22use crate::dom::bindings::root::DomRoot;
23use crate::dom::bindings::str::{DOMString, USVString};
24use crate::dom::globalscope::GlobalScope;
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 cx: &mut JSContext,
41 global: &GlobalScope,
42 proto: Option<HandleObject>,
43 ) -> DomRoot<TextEncoder> {
44 reflect_dom_object_with_proto(cx, Box::new(TextEncoder::new_inherited()), global, proto)
45 }
46}
47
48impl TextEncoderMethods<crate::DomTypeHolder> for TextEncoder {
49 fn Constructor(
51 cx: &mut JSContext,
52 global: &GlobalScope,
53 proto: Option<HandleObject>,
54 ) -> Fallible<DomRoot<TextEncoder>> {
55 Ok(TextEncoder::new(cx, global, proto))
56 }
57
58 fn Encoding(&self) -> DOMString {
60 DOMString::from("utf-8")
61 }
62
63 fn Encode(&self, cx: &mut JSContext, input: USVString) -> RootedTraceableBox<HeapUint8Array> {
65 let encoded = input.0.as_bytes();
66
67 rooted!(&in(cx) let mut js_object = ptr::null_mut::<JSObject>());
68 create_buffer_source(cx, encoded, js_object.handle_mut())
69 .expect("Converting input to uint8 array should never fail")
70 }
71
72 fn EncodeInto(
74 &self,
75 no_gc: &NoGC,
76 source: USVString,
77 mut destination: CustomAutoRooterGuard<typedarray::Uint8Array>,
78 ) -> TextEncoderEncodeIntoResult {
79 let dest = destination.as_mut_slice_safe(no_gc).unwrap_or(&mut []);
80
81 let available = dest.len();
82
83 if available == 0 {
85 return TextEncoderEncodeIntoResult {
86 read: Some(0),
87 written: Some(0),
88 };
89 }
90
91 let mut read = 0;
92 let mut written = 0;
93
94 for result in source.0.chars() {
98 let utf8_len = result.len_utf8();
99 if available - written >= utf8_len {
100 read += if result > '\u{FFFF}' { 2 } else { 1 };
103
104 let target = &mut dest[written..written + utf8_len];
106 result.encode_utf8(target);
107
108 written += utf8_len;
110 } else {
111 break;
114 }
115 }
116
117 TextEncoderEncodeIntoResult {
118 read: Some(read),
119 written: Some(written as _),
120 }
121 }
122}