Skip to content

Commit

Permalink
Added Support for ArrayBuffers
Browse files Browse the repository at this point in the history
Renamed String Functions
Simplified External Strings
  • Loading branch information
Redfire75369 committed Nov 27, 2023
1 parent 3f81907 commit 6b7f57d
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 107 deletions.
1 change: 1 addition & 0 deletions cli/src/commands/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::io;
use std::path::Path;

use humansize::{BINARY, SizeFormatter};

use runtime::cache::Cache;

pub(crate) fn cache_statistics() {
Expand Down
4 changes: 2 additions & 2 deletions ion/src/conversions/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ impl<'cx> ToPropertyKey<'cx> for String<'cx> {

impl<'cx> ToPropertyKey<'cx> for RustString {
fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
String::new(cx, self)?.to_key(cx)
String::copy_from_str(cx, self)?.to_key(cx)
}
}

impl<'cx> ToPropertyKey<'cx> for &str {
fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
String::new(cx, self)?.to_key(cx)
String::copy_from_str(cx, self)?.to_key(cx)
}
}

Expand Down
2 changes: 1 addition & 1 deletion ion/src/conversions/value/to.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl<'cx> ToValue<'cx> for crate::String<'cx> {

impl ToValue<'_> for str {
fn to_value(&self, cx: &Context, value: &mut Value) {
let string = crate::String::new(cx, self);
let string = crate::String::copy_from_str(cx, self);
if let Some(string) = string {
string.to_value(cx, value);
} else {
Expand Down
2 changes: 1 addition & 1 deletion ion/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub struct ModuleRequest<'r>(Object<'r>);
impl<'r> ModuleRequest<'r> {
/// Creates a new [ModuleRequest] with a given specifier.
pub fn new<S: AsRef<str>>(cx: &'r Context, specifier: S) -> ModuleRequest<'r> {
let specifier = crate::String::new(cx, specifier.as_ref()).unwrap();
let specifier = crate::String::copy_from_str(cx, specifier.as_ref()).unwrap();
ModuleRequest(
cx.root_object(unsafe { CreateModuleRequest(cx.as_ptr(), specifier.handle().into()) })
.into(),
Expand Down
2 changes: 1 addition & 1 deletion ion/src/objects/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl<'k> PropertyKey<'k> {

/// Creates a [PropertyKey] from a string.
pub fn with_string(cx: &'k Context, string: &str) -> Option<PropertyKey<'k>> {
let string = String::new(cx, string)?;
let string = String::copy_from_str(cx, string)?;
string.to_key(cx)
}

Expand Down
181 changes: 181 additions & 0 deletions ion/src/objects/typedarray/buffer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

use std::{ptr, slice};
use std::ffi::c_void;
use std::ops::{Deref, DerefMut};

use mozjs::jsapi::{
ArrayBufferClone, ArrayBufferCopyData, DetachArrayBuffer, GetArrayBufferLengthAndData, IsArrayBufferObject,
IsDetachedArrayBufferObject, JS_GetTypedArraySharedness, JSObject, NewExternalArrayBuffer,
};
use mozjs::typedarray::CreateWith;
use mozjs_sys::jsapi::JS::{NewArrayBufferWithContents, StealArrayBufferContents};

use crate::{Context, Error, ErrorKind, Local, Object, Result};
use crate::utils::BoxExt;

pub struct ArrayBuffer<'ab> {
buffer: Local<'ab, *mut JSObject>,
}

impl<'ab> ArrayBuffer<'ab> {
fn create_with(cx: &'ab Context, with: CreateWith<u8>) -> Option<ArrayBuffer<'ab>> {
let mut buffer = Object::null(cx);
unsafe { mozjs::typedarray::ArrayBuffer::create(cx.as_ptr(), with, buffer.handle_mut()).ok()? };
Some(ArrayBuffer { buffer: buffer.into_local() })
}

/// Creates a new [ArrayBuffer] with the given length.
pub fn new(cx: &Context, len: usize) -> Option<ArrayBuffer> {
ArrayBuffer::create_with(cx, CreateWith::Length(len))
}

/// Creates a new [ArrayBuffer] by copying the contents of the given slice.
pub fn copy_from_bytes(cx: &'ab Context, bytes: &[u8]) -> Option<ArrayBuffer<'ab>> {
ArrayBuffer::create_with(cx, CreateWith::Slice(bytes))
}

/// Creates a new [ArrayBuffer] by transferring ownership of the bytes to the JS runtime.
pub fn from_vec(cx: &Context, bytes: Vec<u8>) -> Option<ArrayBuffer> {
ArrayBuffer::from_boxed_slice(cx, bytes.into_boxed_slice())
}

/// Creates a new [ArrayBuffer] by transferring ownership of the bytes to the JS runtime.
pub fn from_boxed_slice(cx: &Context, bytes: Box<[u8]>) -> Option<ArrayBuffer> {
unsafe extern "C" fn free_external_array_buffer(contents: *mut c_void, data: *mut c_void) {
let _ = unsafe { Box::from_raw_parts(contents.cast::<u8>(), data as usize) };
}

let (ptr, len) = unsafe { Box::into_raw_parts(bytes) };
let buffer = unsafe {
NewExternalArrayBuffer(
cx.as_ptr(),
len,
ptr.cast(),
Some(free_external_array_buffer),
len as *mut c_void,
)
};

if buffer.is_null() {
None
} else {
Some(ArrayBuffer { buffer: cx.root_object(buffer) })
}
}

pub fn from(object: Local<'ab, *mut JSObject>) -> Option<ArrayBuffer<'ab>> {
if ArrayBuffer::is_array_buffer(object.get()) {
Some(ArrayBuffer { buffer: object })
} else {
None
}
}

pub unsafe fn from_unchecked(object: Local<'ab, *mut JSObject>) -> ArrayBuffer<'ab> {
ArrayBuffer { buffer: object }
}

/// Returns a pointer and length to the contents of the [ArrayBuffer].
///
/// The pointer may be invalidated if the [ArrayBuffer] is detached.
pub fn data(&self) -> (*mut u8, usize) {
let mut len = 0;
let mut shared = false;
let mut data = ptr::null_mut();
unsafe { GetArrayBufferLengthAndData(self.get(), &mut len, &mut shared, &mut data) };
(data, len)
}

/// Returns a slice to the contents of the [ArrayBuffer].
///
/// The slice may be invalidated if the [ArrayBuffer] is detached.
pub unsafe fn as_slice(&self) -> &[u8] {
let (ptr, len) = self.data();
unsafe { slice::from_raw_parts(ptr, len) }
}

/// Returns a mutable slice to the contents of the [ArrayBuffer].
///
/// The slice may be invalidated if the [ArrayBuffer] is detached.
pub unsafe fn as_mut_slice(&mut self) -> &mut [u8] {
let (ptr, len) = self.data();
unsafe { slice::from_raw_parts_mut(ptr, len) }
}

/// Clones an [ArrayBuffer].
pub fn clone<'cx>(&self, cx: &'cx Context, offset: usize, len: usize) -> Option<ArrayBuffer<'cx>> {
let buffer = unsafe { ArrayBufferClone(cx.as_ptr(), self.handle().into(), offset, len) };
if buffer.is_null() {
None
} else {
Some(ArrayBuffer { buffer: cx.root_object(buffer) })
}
}

/// Copies data from one [ArrayBuffer] to another.
/// Returns `false` if the sizes do not match.
pub fn copy_data_to(
&self, cx: &Context, to: &mut ArrayBuffer, from_index: usize, to_index: usize, count: usize,
) -> bool {
unsafe {
ArrayBufferCopyData(
cx.as_ptr(),
to.handle().into(),
to_index,
self.handle().into(),
from_index,
count,
)
}
}

pub fn detach(&mut self, cx: &Context) -> bool {
unsafe { DetachArrayBuffer(cx.as_ptr(), self.handle().into()) }
}

pub fn transfer<'cx>(&mut self, cx: &'cx Context) -> Result<ArrayBuffer<'cx>> {
let len = self.data().1;
let data = unsafe { StealArrayBufferContents(cx.as_ptr(), self.handle().into()) };
if data.is_null() {
return Err(Error::new("ArrayBuffer transfer failed", ErrorKind::Normal));
}
let buffer = cx.root_object(unsafe { NewArrayBufferWithContents(cx.as_ptr(), len, data) });
if buffer.handle().is_null() {
return Err(Error::new("ArrayBuffer transfer failed", ErrorKind::Normal));
}
Ok(ArrayBuffer { buffer })
}

pub fn is_detached(&self) -> bool {
unsafe { IsDetachedArrayBufferObject(self.get()) }
}

pub fn is_shared(&self) -> bool {
unsafe { JS_GetTypedArraySharedness(self.get()) }
}

/// Checks if an object is an array buffer.
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn is_array_buffer(object: *mut JSObject) -> bool {
unsafe { IsArrayBufferObject(object) }
}
}

impl<'ab> Deref for ArrayBuffer<'ab> {
type Target = Local<'ab, *mut JSObject>;

fn deref(&self) -> &Self::Target {
&self.buffer
}
}

impl<'ab> DerefMut for ArrayBuffer<'ab> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.buffer
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use crate::{Context, Error, Object, Result, Value};
use crate::conversions::ToValue;
use crate::exception::ThrowException;

pub mod buffer;

macro_rules! impl_typedarray_wrapper {
($typedarray:ident, $ty:ty) => {
pub struct $typedarray {
Expand Down
90 changes: 0 additions & 90 deletions ion/src/string/external.rs

This file was deleted.

Loading

0 comments on commit 6b7f57d

Please sign in to comment.