use std::borrow::ToOwned;
use std::default::Default;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::str::FromStr;
use std::{fmt, ops, slice, str};
use js::gc::{HandleObject, HandleValue};
use js::rust::wrappers::ToJSON;
pub use crate::domstring::DOMString;
use crate::error::Error;
use crate::script_runtime::JSContext;
#[derive(Clone, Debug, Default, Eq, JSTraceable, MallocSizeOf, PartialEq)]
pub struct ByteString(Vec<u8>);
impl ByteString {
pub fn new(value: Vec<u8>) -> ByteString {
ByteString(value)
}
pub fn as_str(&self) -> Option<&str> {
str::from_utf8(&self.0).ok()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn to_lower(&self) -> ByteString {
ByteString::new(self.0.to_ascii_lowercase())
}
}
impl From<ByteString> for Vec<u8> {
fn from(byte_string: ByteString) -> Vec<u8> {
byte_string.0
}
}
impl Hash for ByteString {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl FromStr for ByteString {
type Err = ();
fn from_str(s: &str) -> Result<ByteString, ()> {
Ok(ByteString::new(s.to_owned().into_bytes()))
}
}
impl ops::Deref for ByteString {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.0
}
}
#[derive(Clone, Debug, Default, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd)]
pub struct USVString(pub String);
impl Deref for USVString {
type Target = str;
#[inline]
fn deref(&self) -> &str {
&self.0
}
}
impl AsRef<str> for USVString {
fn as_ref(&self) -> &str {
&self.0
}
}
impl fmt::Display for USVString {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl PartialEq<str> for USVString {
fn eq(&self, other: &str) -> bool {
self.0 == other
}
}
impl<'a> PartialEq<&'a str> for USVString {
fn eq(&self, other: &&'a str) -> bool {
self.0 == *other
}
}
impl From<String> for USVString {
fn from(contents: String) -> USVString {
USVString(contents)
}
}
impl From<USVString> for String {
fn from(value: USVString) -> Self {
value.0
}
}
impl From<USVString> for DOMString {
fn from(value: USVString) -> Self {
value.0.into()
}
}
pub fn is_token(s: &[u8]) -> bool {
if s.is_empty() {
return false; }
s.iter().all(|&x| {
match x {
0..=31 | 127 => false, 40 | 41 | 60 | 62 | 64 | 44 | 59 | 58 | 92 | 34 | 47 | 91 | 93 | 63 | 61 | 123 |
125 | 32 => false, x if x > 127 => false, _ => true,
}
})
}
pub fn serialize_jsval_to_json_utf8(cx: JSContext, data: HandleValue) -> Result<DOMString, Error> {
#[repr(C)]
struct ToJSONCallbackData {
string: Option<String>,
}
let mut out_str = ToJSONCallbackData { string: None };
#[expect(unsafe_code)]
unsafe extern "C" fn write_callback(
string: *const u16,
len: u32,
data: *mut std::ffi::c_void,
) -> bool {
let data = data as *mut ToJSONCallbackData;
let string_chars = unsafe { slice::from_raw_parts(string, len as usize) };
unsafe { &mut *data }
.string
.get_or_insert_with(Default::default)
.push_str(&String::from_utf16_lossy(string_chars));
true
}
unsafe {
let stringify_result = ToJSON(
*cx,
data,
HandleObject::null(),
HandleValue::null(),
Some(write_callback),
&mut out_str as *mut ToJSONCallbackData as *mut _,
);
if !stringify_result {
return Err(Error::JSFailed);
}
}
out_str
.string
.map(Into::into)
.ok_or_else(|| Error::Type(c"unable to serialize JSON".to_owned()))
}