use anyhow::Result;
use rusty_v8 as v8;
use std::sync::atomic::{AtomicUsize, Ordering};
static SHARED_BUFFER_COUNT: AtomicUsize = AtomicUsize::new(0);
pub fn get_shared_buffer_count() -> usize {
SHARED_BUFFER_COUNT.load(Ordering::SeqCst)
}
pub fn setup_shared_array_buffer_api(
scope: &mut v8::ContextScope<v8::HandleScope>,
context: &v8::Local<v8::Context>,
) -> Result<()> {
let global = context.global(scope);
let shared_buffer_key = v8::String::new(scope, "SharedArrayBuffer").unwrap();
if let Some(shared_buffer_val) = global.get(scope, shared_buffer_key.into()) {
if shared_buffer_val.is_function() {
return Ok(());
}
}
let shared_buffer_constructor = v8::FunctionTemplate::new(scope, shared_array_buffer_callback);
let shared_buffer_func = shared_buffer_constructor.get_function(scope).unwrap();
global.set(scope, shared_buffer_key.into(), shared_buffer_func.into());
Ok(())
}
fn shared_array_buffer_callback(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
let first = args.get(0);
if !first.is_number() {
let error = v8::String::new(scope, "SharedArrayBuffer: byteLength is required").unwrap();
let exception = v8::Exception::type_error(scope, error);
scope.throw_exception(exception);
return;
}
let size = first.to_integer(scope).unwrap().value() as usize;
if size == 0 {
if let Some(buffer) = v8::SharedArrayBuffer::new(scope, 0) {
SHARED_BUFFER_COUNT.fetch_add(1, Ordering::SeqCst);
retval.set(buffer.into());
} else {
let undefined: v8::Local<v8::Value> = v8::undefined(scope).into();
retval.set(undefined);
}
return;
}
const MAX_SIZE: usize = 1024 * 1024 * 1024; if size > MAX_SIZE {
let error = v8::String::new(
scope,
&format!(
"SharedArrayBuffer: size {} exceeds maximum allowed ({})",
size, MAX_SIZE
),
)
.unwrap();
let exception = v8::Exception::range_error(scope, error);
scope.throw_exception(exception);
return;
}
if let Some(buffer) = v8::SharedArrayBuffer::new(scope, size) {
SHARED_BUFFER_COUNT.fetch_add(1, Ordering::SeqCst);
retval.set(buffer.into());
} else {
let error = v8::String::new(scope, "SharedArrayBuffer: allocation failed").unwrap();
let exception = v8::Exception::range_error(scope, error);
scope.throw_exception(exception);
}
}
pub fn get_shared_buffer_byte_length(buffer: v8::Local<v8::SharedArrayBuffer>) -> usize {
buffer.byte_length()
}
pub fn is_shared_array_buffer(value: v8::Local<v8::Value>) -> bool {
value.is_shared_array_buffer()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_shared_buffer_count_initial() {
assert_eq!(get_shared_buffer_count(), 0);
}
}