1use std::borrow::ToOwned;
7use std::default::Default;
8use std::hash::{Hash, Hasher};
9use std::ops::Deref;
10use std::str::FromStr;
11use std::{fmt, ops, slice, str};
12
13use js::context::JSContext;
14use js::gc::{HandleObject, HandleValue};
15use js::rust::wrappers2::ToJSON;
16
17pub use crate::domstring::DOMString;
18use crate::error::Error;
19
20#[derive(Clone, Debug, Default, Eq, JSTraceable, MallocSizeOf, PartialEq)]
22pub struct ByteString(Vec<u8>);
23
24impl ByteString {
25 pub fn new(value: Vec<u8>) -> ByteString {
27 ByteString(value)
28 }
29
30 pub fn as_str(&self) -> Option<&str> {
33 str::from_utf8(&self.0).ok()
34 }
35
36 pub fn len(&self) -> usize {
38 self.0.len()
39 }
40
41 pub fn is_empty(&self) -> bool {
43 self.0.is_empty()
44 }
45
46 pub fn to_lower(&self) -> ByteString {
48 ByteString::new(self.0.to_ascii_lowercase())
49 }
50}
51
52impl From<ByteString> for Vec<u8> {
53 fn from(byte_string: ByteString) -> Vec<u8> {
54 byte_string.0
55 }
56}
57
58impl Hash for ByteString {
59 fn hash<H: Hasher>(&self, state: &mut H) {
60 self.0.hash(state);
61 }
62}
63
64impl FromStr for ByteString {
65 type Err = ();
66 fn from_str(s: &str) -> Result<ByteString, ()> {
67 Ok(ByteString::new(s.to_owned().into_bytes()))
68 }
69}
70
71impl ops::Deref for ByteString {
72 type Target = [u8];
73 fn deref(&self) -> &[u8] {
74 &self.0
75 }
76}
77
78#[derive(Clone, Debug, Default, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd)]
81pub struct USVString(pub String);
82
83impl USVString {
84 pub fn new() -> USVString {
86 USVString(String::new())
87 }
88}
89
90impl Deref for USVString {
91 type Target = str;
92
93 #[inline]
94 fn deref(&self) -> &str {
95 &self.0
96 }
97}
98
99impl AsRef<str> for USVString {
100 fn as_ref(&self) -> &str {
101 &self.0
102 }
103}
104
105impl fmt::Display for USVString {
106 #[inline]
107 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108 fmt::Display::fmt(&self.0, f)
109 }
110}
111
112impl PartialEq<str> for USVString {
113 fn eq(&self, other: &str) -> bool {
114 self.0 == other
115 }
116}
117
118impl<'a> PartialEq<&'a str> for USVString {
119 fn eq(&self, other: &&'a str) -> bool {
120 self.0 == *other
121 }
122}
123
124impl From<String> for USVString {
125 fn from(contents: String) -> USVString {
126 USVString(contents)
127 }
128}
129
130impl From<USVString> for String {
131 fn from(value: USVString) -> Self {
132 value.0
133 }
134}
135
136impl From<USVString> for DOMString {
137 fn from(value: USVString) -> Self {
138 value.0.into()
139 }
140}
141
142pub fn is_token(s: &[u8]) -> bool {
145 if s.is_empty() {
146 return false; }
148 s.iter().all(|&x| {
149 match x {
151 0..=31 | 127 => false, 40 | 41 | 60 | 62 | 64 | 44 | 59 | 58 | 92 | 34 | 47 | 91 | 93 | 63 | 61 | 123 |
153 125 | 32 => false, x if x > 127 => false, _ => true,
156 }
157 })
158}
159
160pub fn serialize_jsval_to_json_utf8(
166 cx: &mut JSContext,
167 data: HandleValue,
168) -> Result<DOMString, Error> {
169 #[repr(C)]
170 struct ToJSONCallbackData {
171 string: Option<String>,
172 }
173
174 let mut out_str = ToJSONCallbackData { string: None };
175
176 #[expect(unsafe_code)]
177 unsafe extern "C" fn write_callback(
178 string: *const u16,
179 len: u32,
180 data: *mut std::ffi::c_void,
181 ) -> bool {
182 let data = data as *mut ToJSONCallbackData;
183 let string_chars = unsafe { slice::from_raw_parts(string, len as usize) };
184 unsafe { &mut *data }
185 .string
186 .get_or_insert_with(Default::default)
187 .push_str(&String::from_utf16_lossy(string_chars));
188 true
189 }
190
191 unsafe {
193 let stringify_result = ToJSON(
194 cx,
195 data,
196 HandleObject::null(),
197 HandleValue::null(),
198 Some(write_callback),
199 &mut out_str as *mut ToJSONCallbackData as *mut _,
200 );
201 if !stringify_result {
204 return Err(Error::JSFailed);
205 }
206 }
207
208 out_str
213 .string
214 .map(Into::into)
215 .ok_or_else(|| Error::Type(c"unable to serialize JSON".to_owned()))
216}