use crate::{
ecmascript::{DataBlock, OrdinaryObject},
engine::bindable_handle,
heap::{CompactionLists, HeapMarkAndSweep, WorkQueues},
};
#[repr(transparent)]
#[derive(Clone, Copy, Eq, PartialEq)]
pub(crate) struct ViewedArrayBufferByteLength(pub u32);
impl core::fmt::Debug for ViewedArrayBufferByteLength {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_auto() {
f.write_str("AUTO")
} else if self.is_overflowing() {
f.write_str("> u32::MAX - 2")
} else {
self.0.fmt(f)
}
}
}
impl ViewedArrayBufferByteLength {
pub(crate) const fn is_overflowing(self) -> bool {
self.0 == Self::heap().0
}
pub(crate) const fn is_auto(self) -> bool {
self.0 == Self::auto().0
}
pub const fn value(value: u32) -> Self {
Self(value)
}
pub const fn heap() -> Self {
Self(u32::MAX - 1)
}
pub const fn auto() -> Self {
Self(u32::MAX)
}
}
impl Default for ViewedArrayBufferByteLength {
fn default() -> Self {
Self::auto()
}
}
impl From<Option<usize>> for ViewedArrayBufferByteLength {
fn from(value: Option<usize>) -> Self {
match value {
Some(value) => Self::from(value),
None => Self::auto(),
}
}
}
impl From<usize> for ViewedArrayBufferByteLength {
fn from(value: usize) -> Self {
if value >= Self::heap().0 as usize {
Self::heap()
} else {
Self::value(value as u32)
}
}
}
#[repr(transparent)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub(crate) struct ViewedArrayBufferByteOffset(pub u32);
impl ViewedArrayBufferByteOffset {
pub(crate) const fn value(value: u32) -> Self {
Self(value)
}
pub(crate) fn is_overflowing(self) -> bool {
self.0 == Self::heap().0
}
pub(crate) const fn heap() -> Self {
Self(u32::MAX)
}
}
impl Default for ViewedArrayBufferByteOffset {
fn default() -> Self {
Self::value(0)
}
}
impl From<usize> for ViewedArrayBufferByteOffset {
fn from(value: usize) -> Self {
if value >= Self::heap().0 as usize {
Self::heap()
} else {
Self::value(value as u32)
}
}
}
#[derive(Debug)]
pub(crate) struct InternalBuffer {
data_block: DataBlock,
capacity: usize,
}
impl InternalBuffer {
pub(crate) fn get_data_block(&self) -> &DataBlock {
if self.data_block.is_detached() {
unreachable!();
}
&self.data_block
}
pub(crate) fn get_data_block_mut(&mut self) -> &mut DataBlock {
if self.data_block.is_detached() {
unreachable!();
}
&mut self.data_block
}
pub(crate) fn detach(&mut self) {
self.capacity = 0;
self.data_block = DataBlock::DETACHED_DATA_BLOCK;
}
const fn detached() -> Self {
Self {
data_block: DataBlock::DETACHED_DATA_BLOCK,
capacity: usize::MAX,
}
}
pub(crate) fn fixed_length(data_block: DataBlock) -> Self {
Self {
data_block,
capacity: usize::MAX,
}
}
pub(crate) fn resizable(data_block: DataBlock, capacity: usize) -> Self {
assert_ne!(capacity, usize::MAX);
Self {
data_block,
capacity,
}
}
}
#[derive(Debug)]
pub(crate) struct ArrayBufferHeapData<'a> {
pub(crate) object_index: Option<OrdinaryObject<'a>>,
pub(super) buffer: InternalBuffer,
}
impl Default for ArrayBufferHeapData<'_> {
#[inline(always)]
fn default() -> Self {
Self {
object_index: None,
buffer: InternalBuffer::detached(),
}
}
}
unsafe impl Send for ArrayBufferHeapData<'_> {}
impl<'a> ArrayBufferHeapData<'a> {
pub(crate) fn new_fixed_length(db: DataBlock) -> Self {
Self {
object_index: None,
buffer: InternalBuffer::fixed_length(db),
}
}
pub(crate) fn get_data_block(&self) -> &DataBlock {
&self.buffer.data_block
}
pub(crate) fn get_data_block_mut(&mut self) -> &mut DataBlock {
&mut self.buffer.data_block
}
pub(crate) fn is_detached(&self) -> bool {
self.buffer.data_block.is_detached()
}
pub(crate) fn is_resizable(&self) -> bool {
self.buffer.capacity != usize::MAX
}
pub(crate) fn byte_length(&self) -> usize {
if self.is_detached() {
0
} else {
self.buffer.data_block.len()
}
}
pub(crate) fn max_byte_length(&self) -> usize {
if self.is_detached() {
0
} else if self.is_resizable() {
self.buffer.capacity
} else {
self.buffer.data_block.len()
}
}
pub(crate) fn resize(&mut self, new_byte_length: usize) {
if self.is_resizable() {
self.buffer.data_block.realloc(new_byte_length);
} else {
unreachable!();
}
}
}
bindable_handle!(ArrayBufferHeapData);
impl HeapMarkAndSweep for ArrayBufferHeapData<'static> {
fn mark_values(&self, queues: &mut WorkQueues) {
let Self {
object_index,
buffer: _,
} = self;
object_index.mark_values(queues);
}
fn sweep_values(&mut self, compactions: &CompactionLists) {
let Self {
object_index,
buffer: _,
} = self;
object_index.sweep_values(compactions);
}
}