mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 新增 SharedBuffer 共享字节缓冲与核账目
This commit is contained in:
Generated
+19
-19
@@ -1160,7 +1160,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_builtins"
|
name = "oxide_builtins"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"fast-float",
|
"fast-float",
|
||||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_bytecode"
|
name = "oxide_bytecode"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"oxide_log",
|
"oxide_log",
|
||||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_cfg"
|
name = "oxide_cfg"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_emit",
|
"oxide_emit",
|
||||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_cli"
|
name = "oxide_cli"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
"ansi_term",
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
@@ -1226,7 +1226,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_code_cache"
|
name = "oxide_code_cache"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lru",
|
"lru",
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
@@ -1235,7 +1235,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_compiler"
|
name = "oxide_compiler"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1255,7 +1255,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_dce"
|
name = "oxide_dce"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1269,7 +1269,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_emit"
|
name = "oxide_emit"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
@@ -1284,7 +1284,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_engine"
|
name = "oxide_engine"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_compiler",
|
"oxide_compiler",
|
||||||
@@ -1296,7 +1296,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_ir"
|
name = "oxide_ir"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_log",
|
"oxide_log",
|
||||||
@@ -1305,7 +1305,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_kernel"
|
name = "oxide_kernel"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
@@ -1319,7 +1319,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_liveness"
|
name = "oxide_liveness"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1331,7 +1331,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_log"
|
name = "oxide_log"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-appender",
|
"tracing-appender",
|
||||||
@@ -1340,7 +1340,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_parser"
|
name = "oxide_parser"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
"oxc_ast",
|
"oxc_ast",
|
||||||
@@ -1355,7 +1355,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_regalloc"
|
name = "oxide_regalloc"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1371,7 +1371,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_runtime_api"
|
name = "oxide_runtime_api"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@@ -1383,7 +1383,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_test262"
|
name = "oxide_test262"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_compiler",
|
"oxide_compiler",
|
||||||
@@ -1401,7 +1401,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_types"
|
name = "oxide_types"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
@@ -1414,7 +1414,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_vm"
|
name = "oxide_vm"
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.8.79"
|
version = "0.8.80"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
rust-version = "1.80"
|
rust-version = "1.80"
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ pub struct KernelCore {
|
|||||||
/// 内创建满 512 个 Vm 前重建 kernel(重建即计数器归零);test262 runner
|
/// 内创建满 512 个 Vm 前重建 kernel(重建即计数器归零);test262 runner
|
||||||
/// 经 kernel_batch 缺省值(不超 512)满足该约束。
|
/// 经 kernel_batch 缺省值(不超 512)满足该约束。
|
||||||
realm_counter: AtomicU32,
|
realm_counter: AtomicU32,
|
||||||
|
/// 共享字节缓冲账目:存活 `SharedBuffer` 的预分配真实上限之和。
|
||||||
|
/// `SharedBuffer` 构造加、`Drop` 减(同值),供宿主读取共享层内存占用。
|
||||||
|
shared_buffer_bytes: AtomicUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KernelCore {
|
impl KernelCore {
|
||||||
@@ -66,6 +69,7 @@ impl KernelCore {
|
|||||||
prop_forge,
|
prop_forge,
|
||||||
active_vms: AtomicUsize::new(0),
|
active_vms: AtomicUsize::new(0),
|
||||||
realm_counter: AtomicU32::new(0),
|
realm_counter: AtomicU32::new(0),
|
||||||
|
shared_buffer_bytes: AtomicUsize::new(0),
|
||||||
});
|
});
|
||||||
kernel_info!("KernelCore initialized: max_cached_modules={}, min_pool={}", max_cached, min_pool);
|
kernel_info!("KernelCore initialized: max_cached_modules={}, min_pool={}", max_cached, min_pool);
|
||||||
core
|
core
|
||||||
@@ -196,6 +200,21 @@ impl KernelCore {
|
|||||||
self.active_vms.load(Ordering::Relaxed)
|
self.active_vms.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 读取存活共享字节缓冲的预分配真实上限之和(字节)。
|
||||||
|
pub fn shared_buffer_bytes(&self) -> usize {
|
||||||
|
self.shared_buffer_bytes.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 共享字节缓冲账目加账(`SharedBuffer` 构造调用;单位是预分配真实上限)。
|
||||||
|
pub(crate) fn shared_buffer_bytes_add(&self, bytes: usize) {
|
||||||
|
self.shared_buffer_bytes.fetch_add(bytes, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 共享字节缓冲账目减账(`SharedBuffer` 析构调用;单位是预分配真实上限)。
|
||||||
|
pub(crate) fn shared_buffer_bytes_sub(&self, bytes: usize) {
|
||||||
|
self.shared_buffer_bytes.fetch_sub(bytes, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
/// 分配一个 realm 编号:取计数器当前值后自增,进程内单调递增。
|
/// 分配一个 realm 编号:取计数器当前值后自增,进程内单调递增。
|
||||||
///
|
///
|
||||||
/// 首个 realm 编号为 0(与旧符号编码一致),供 `Realm` 构造时固化。
|
/// 首个 realm 编号为 0(与旧符号编码一致),供 `Realm` 构造时固化。
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ pub mod kernel_log;
|
|||||||
pub mod prop_forge;
|
pub mod prop_forge;
|
||||||
/// hidden class(shape)共享存储:把对象结构映射为整数 id。
|
/// hidden class(shape)共享存储:把对象结构映射为整数 id。
|
||||||
pub mod shape_forge;
|
pub mod shape_forge;
|
||||||
|
/// 共享字节缓冲:SharedArrayBuffer 的跨线程共享存储(预分配至真实上限,活长原子推进)。
|
||||||
|
pub mod shared_buffer;
|
||||||
|
|
||||||
/// kernel 对外的三个核心类型:配置、共享核心、会话。
|
/// kernel 对外的三个核心类型:配置、共享核心、会话。
|
||||||
pub use kernel::{KernelConfig, KernelCore, KernelSession};
|
pub use kernel::{KernelConfig, KernelCore, KernelSession};
|
||||||
@@ -24,3 +26,5 @@ pub use kernel::{KernelConfig, KernelCore, KernelSession};
|
|||||||
pub use oxide_types::string_forge;
|
pub use oxide_types::string_forge;
|
||||||
/// 模块命名空间再导出的绑定身份哨兵(本体在 `oxide_types`,此处再导出)。
|
/// 模块命名空间再导出的绑定身份哨兵(本体在 `oxide_types`,此处再导出)。
|
||||||
pub use oxide_types::MODULE_NAMESPACE_BINDING;
|
pub use oxide_types::MODULE_NAMESPACE_BINDING;
|
||||||
|
/// 跨线程共享字节缓冲(SharedArrayBuffer 的共享存储)。
|
||||||
|
pub use shared_buffer::SharedBuffer;
|
||||||
|
|||||||
@@ -0,0 +1,247 @@
|
|||||||
|
//! 共享字节缓冲:SharedArrayBuffer 的跨线程共享存储。
|
||||||
|
//!
|
||||||
|
//! 关键约定:
|
||||||
|
//! - 字节区一次性预分配至真实上限并零填充,此后不再重分配;`grow` 只推进活长,O(1)。
|
||||||
|
//! - `write_range` 经 `&self` 裸写(字节区归本结构独占,类型不暴露 `&mut [u8]`),多线程并发写安全。
|
||||||
|
//! - 账目单位是预分配真实上限:构造时计入 `KernelCore::shared_buffer_bytes`,`Drop` 减同值。
|
||||||
|
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::KernelCore;
|
||||||
|
|
||||||
|
/// 共享字节缓冲操作的越界错误。
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum SharedBufferError {
|
||||||
|
/// 写范围超出活长(offset + data 长度 > len)。
|
||||||
|
OutOfRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 跨线程共享字节缓冲:预分配至真实上限,活长经原子推进。
|
||||||
|
///
|
||||||
|
/// 全部字段 `Send + Sync`,可经 `Arc` 跨线程共享;账目入口是结构持有的
|
||||||
|
/// `Arc<KernelCore>`,`Drop` 时从核的 `shared_buffer_bytes` 减预分配真实上限。
|
||||||
|
pub struct SharedBuffer {
|
||||||
|
/// 共享字节区,预分配至真实上限并零填充。
|
||||||
|
bytes: Arc<Vec<u8>>,
|
||||||
|
/// 活字节长(growable 经原子推进)。
|
||||||
|
length: AtomicUsize,
|
||||||
|
/// 预分配真实上限。
|
||||||
|
max_length: usize,
|
||||||
|
/// 账目入口。
|
||||||
|
core: Arc<KernelCore>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SharedBuffer {
|
||||||
|
/// 定长构造:字节序列即活内容,上限即字节序列长度。
|
||||||
|
///
|
||||||
|
/// # 副作用
|
||||||
|
/// - 核的 `shared_buffer_bytes` 加字节序列长度(真实上限)。
|
||||||
|
pub fn new(core: Arc<KernelCore>, bytes: Vec<u8>) -> Self {
|
||||||
|
let bytes = Arc::new(bytes);
|
||||||
|
let len = bytes.len();
|
||||||
|
core.shared_buffer_bytes_add(len);
|
||||||
|
Self {
|
||||||
|
bytes,
|
||||||
|
length: AtomicUsize::new(len),
|
||||||
|
max_length: len,
|
||||||
|
core,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 可增长构造:预分配至 `max_len` 并零填充,初始活长 `initial_len`。
|
||||||
|
///
|
||||||
|
/// # 边界与前提
|
||||||
|
/// - `initial_len` 不得超过 `max_len`(debug 构建 fail-fast)。
|
||||||
|
///
|
||||||
|
/// # 副作用
|
||||||
|
/// - 核的 `shared_buffer_bytes` 加 `max_len`(真实上限),而非 `initial_len`。
|
||||||
|
pub fn new_growable(core: Arc<KernelCore>, initial_len: usize, max_len: usize) -> Self {
|
||||||
|
debug_assert!(initial_len <= max_len, "initial_len must not exceed max_len");
|
||||||
|
let bytes = Arc::new(vec![0u8; max_len]);
|
||||||
|
core.shared_buffer_bytes_add(max_len);
|
||||||
|
Self {
|
||||||
|
bytes,
|
||||||
|
length: AtomicUsize::new(initial_len),
|
||||||
|
max_length: max_len,
|
||||||
|
core,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 读取当前活字节长。
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.length.load(Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 判断活区是否为空。
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 读取预分配真实上限。
|
||||||
|
pub fn max_len(&self) -> usize {
|
||||||
|
self.max_length
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 活长区只读切片。
|
||||||
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
|
&self.bytes[..self.len()]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 把 `data` 写入活长区 `offset` 起(经 `&self` 裸写)。
|
||||||
|
///
|
||||||
|
/// # 边界与前提
|
||||||
|
/// - `offset + data.len()` 超过活长时返回 `OutOfRange`,不做任何写入;
|
||||||
|
/// - 写入不改变活长。
|
||||||
|
///
|
||||||
|
/// # 注意事项
|
||||||
|
/// - 字节区归本结构独占且类型不暴露 `&mut [u8]`,经 `&self` 裸写不构成别名;
|
||||||
|
/// 不得新增 `bytes_mut` 一类方法,否则该前提失效。
|
||||||
|
pub fn write_range(&self, offset: usize, data: &[u8]) -> Result<(), SharedBufferError> {
|
||||||
|
let end = offset.checked_add(data.len()).ok_or(SharedBufferError::OutOfRange)?;
|
||||||
|
if end > self.len() {
|
||||||
|
return Err(SharedBufferError::OutOfRange);
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
// 字节区归本结构独占,裸写目标即其内部可变区。
|
||||||
|
let dest = self.bytes.as_ptr().add(offset) as *mut u8;
|
||||||
|
std::ptr::copy_nonoverlapping(data.as_ptr(), dest, data.len());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 把活长推进到 `new_len`(只增不缩),返回操作后活长。
|
||||||
|
///
|
||||||
|
/// # 边界与前提
|
||||||
|
/// - 缩长(`new_len` 不大于当前活长)与超上限(`new_len` 大于 `max_len`)均被拒绝,
|
||||||
|
/// 返回当前活长;
|
||||||
|
/// - 字节区已预分配,推进只改原子计数,O(1)。
|
||||||
|
///
|
||||||
|
/// # 副作用
|
||||||
|
/// - 经 CAS 循环推进 `length`;并发调用各自至多推进一次。
|
||||||
|
pub fn grow(&self, new_len: usize) -> usize {
|
||||||
|
let mut cur = self.length.load(Ordering::SeqCst);
|
||||||
|
loop {
|
||||||
|
// 缩长与超上限统一拒绝,返回当前活长。
|
||||||
|
if new_len <= cur || new_len > self.max_length {
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
match self
|
||||||
|
.length
|
||||||
|
.compare_exchange_weak(cur, new_len, Ordering::SeqCst, Ordering::SeqCst)
|
||||||
|
{
|
||||||
|
Ok(_) => return new_len,
|
||||||
|
Err(next) => cur = next,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for SharedBuffer {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// 账目单位与构造时加账一致:预分配真实上限。
|
||||||
|
self.core.shared_buffer_bytes_sub(self.bytes.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::KernelConfig;
|
||||||
|
|
||||||
|
fn new_core() -> Arc<KernelCore> {
|
||||||
|
KernelCore::new(KernelConfig::minimal())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shared_buffer_is_send_sync() {
|
||||||
|
fn assert_send_sync<T: Send + Sync>() {}
|
||||||
|
assert_send_sync::<SharedBuffer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn new_fixed_size_len_and_accounting() {
|
||||||
|
let core = new_core();
|
||||||
|
let buf = SharedBuffer::new(core.clone(), vec![1, 2, 3, 4]);
|
||||||
|
assert_eq!(buf.len(), 4);
|
||||||
|
assert_eq!(buf.max_len(), 4);
|
||||||
|
assert_eq!(buf.as_slice(), &[1, 2, 3, 4]);
|
||||||
|
assert_eq!(core.shared_buffer_bytes(), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn new_growable_preallocates_to_max() {
|
||||||
|
let core = new_core();
|
||||||
|
let buf = SharedBuffer::new_growable(core.clone(), 2, 8);
|
||||||
|
assert_eq!(buf.len(), 2);
|
||||||
|
assert_eq!(buf.max_len(), 8);
|
||||||
|
assert_eq!(buf.as_slice(), &[0, 0]);
|
||||||
|
// 账目单位是预分配真实上限,而非初始活长。
|
||||||
|
assert_eq!(core.shared_buffer_bytes(), 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn write_range_updates_live_region() {
|
||||||
|
let core = new_core();
|
||||||
|
let buf = SharedBuffer::new(core, vec![0u8; 8]);
|
||||||
|
buf.write_range(2, &[9, 8, 7]).unwrap();
|
||||||
|
assert_eq!(buf.as_slice(), &[0, 0, 9, 8, 7, 0, 0, 0]);
|
||||||
|
assert_eq!(buf.len(), 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn write_range_rejects_out_of_range() {
|
||||||
|
let core = new_core();
|
||||||
|
let buf = SharedBuffer::new(core, vec![0u8; 4]);
|
||||||
|
assert_eq!(buf.write_range(3, &[1, 2]), Err(SharedBufferError::OutOfRange));
|
||||||
|
// offset 溢出加法同样按越界处理。
|
||||||
|
assert_eq!(buf.write_range(usize::MAX, &[1]), Err(SharedBufferError::OutOfRange));
|
||||||
|
// 拒绝时活长不变。
|
||||||
|
assert_eq!(buf.len(), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn grow_only_increases_and_caps_at_max() {
|
||||||
|
let core = new_core();
|
||||||
|
let buf = SharedBuffer::new_growable(core, 2, 8);
|
||||||
|
assert_eq!(buf.grow(5), 5);
|
||||||
|
assert_eq!(buf.as_slice(), &[0, 0, 0, 0, 0]);
|
||||||
|
// 缩长被拒绝,活长不变。
|
||||||
|
assert_eq!(buf.grow(3), 5);
|
||||||
|
// 超上限被拒绝,活长不变。
|
||||||
|
assert_eq!(buf.grow(9), 5);
|
||||||
|
// 恰好到上限成功。
|
||||||
|
assert_eq!(buf.grow(8), 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn drop_returns_accounting_to_zero() {
|
||||||
|
let core = new_core();
|
||||||
|
{
|
||||||
|
let fixed = SharedBuffer::new(core.clone(), vec![0u8; 4]);
|
||||||
|
// 作用域末隐式析构,验证减账归零。
|
||||||
|
let _growable = SharedBuffer::new_growable(core.clone(), 0, 16);
|
||||||
|
assert_eq!(core.shared_buffer_bytes(), 20);
|
||||||
|
drop(fixed);
|
||||||
|
assert_eq!(core.shared_buffer_bytes(), 16);
|
||||||
|
}
|
||||||
|
assert_eq!(core.shared_buffer_bytes(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn arc_shared_across_threads() {
|
||||||
|
let core = new_core();
|
||||||
|
let buf = Arc::new(SharedBuffer::new_growable(core, 0, 16));
|
||||||
|
let child = {
|
||||||
|
let buf = Arc::clone(&buf);
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
buf.grow(8);
|
||||||
|
buf.write_range(4, &[0xAB, 0xCD]).unwrap();
|
||||||
|
buf.len()
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let len = child.join().unwrap();
|
||||||
|
assert_eq!(len, 8);
|
||||||
|
assert_eq!(buf.as_slice(), &[0, 0, 0, 0, 0xAB, 0xCD, 0, 0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user