use rong::*;
#[js_class]
pub struct TextEncoder {}
#[js_class]
impl TextEncoder {
#[js_method(constructor)]
fn new() -> Self {
Self {}
}
#[js_method(getter, enumerable)]
fn encoding(&self) -> String {
"utf-8".to_string()
}
#[js_method]
fn encode(&self, ctx: JSContext, input: JSValue) -> JSResult<JSTypedArray> {
let input = if input.is_undefined() || input.is_null() {
String::new()
} else {
input.to_rust::<String>()?
};
let bytes = input.as_bytes();
let buffer = JSArrayBuffer::from_bytes(&ctx, bytes)?;
JSTypedArray::<u8>::from_array_buffer(&ctx, buffer, 0, Some(bytes.len()))
}
#[js_method(rename = "encodeInto")]
fn encode_into(&self, ctx: JSContext, input: String, dest: JSObject) -> JSResult<JSObject> {
if let Some(typed_array) = AnyJSTypedArray::from_object(dest) {
if typed_array.kind() == JSTypedArrayKind::Uint8 {
let byte_offset = typed_array.byte_offset();
let buffer_len = typed_array.byte_length();
let mut buffer = typed_array.buffer()?;
let buffer_end = byte_offset.checked_add(buffer_len).ok_or_else(|| {
HostError::new(
rong::error::E_OUT_OF_RANGE,
"Uint8Array view range overflow",
)
.with_name("RangeError")
})?;
let buffer_data = buffer
.as_mut_slice()
.get_mut(byte_offset..buffer_end)
.ok_or_else(|| {
HostError::new(
rong::error::E_OUT_OF_RANGE,
"Uint8Array view exceeds its backing buffer",
)
.with_name("RangeError")
})?;
let mut read = 0usize;
let mut written = 0usize;
for ch in input.chars() {
let encoded_len = ch.len_utf8();
let Some(end) = written.checked_add(encoded_len) else {
break;
};
if end > buffer_data.len() {
break;
}
let mut encoded = [0u8; 4];
let bytes = ch.encode_utf8(&mut encoded).as_bytes();
buffer_data[written..end].copy_from_slice(bytes);
written = end;
read += ch.len_utf16();
}
let result = JSObject::new(&ctx);
result.set("read", read as f64)?;
result.set("written", written as f64)?;
return Ok(result);
}
}
Err(HostError::new(
rong::error::E_INVALID_ARG,
"The \"dest\" argument must be an instance of Uint8Array.",
)
.with_name("TypeError")
.into())
}
#[js_method(gc_mark)]
fn gc_mark_with<F>(&self, _mark_fn: F)
where
F: FnMut(&JSValue),
{
}
}
impl Default for TextEncoder {
fn default() -> Self {
Self::new()
}
}
pub(crate) fn init(ctx: &JSContext) -> JSResult<()> {
ctx.register_class::<TextEncoder>()?;
Ok(())
}