1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//! Zero-copy `ArrayBuffer` helpers built on QuickJS-NG primitives.
//!
//! `rquickjs` doesn't yet ship safe wrappers for QuickJS-NG's
//! [immutable ArrayBuffer](https://tc39.es/proposal-immutable-arraybuffer/)
//! support, so we go through `rquickjs::qjs::*` directly. The two
//! capabilities exposed here are:
//!
//! * [`shared_array_buffer_view`] — create a fresh `ArrayBuffer` that
//! borrows the bytes of an existing one (no memcpy), kept alive via a
//! dup'd `JSValue` reference. The view is marked immutable, which is
//! both a correctness guarantee (consumer mutations can't leak into the
//! source) and a hard safety rail (the only QuickJS code path that
//! would lose our refcount handle is `.transfer()`, which immutability
//! blocks at the JS layer).
//! * [`set_immutable`] — flip the immutable flag on an existing
//! `ArrayBuffer` (used when the source is a freshly-allocated buffer
//! we own and want to seal before handing out).
//!
//! These are used by `Blob.stream()` / `Blob.slice()` and by fetch's
//! `Response.body` / `Request.body` getters to hand out aliased,
//! transfer-safe views into producer-owned storage.
use c_void;
use ;
/// Mark an `ArrayBuffer` as immutable: subsequent writes through any
/// `Uint8Array` / `DataView` view silently fail (or `TypeError` in strict
/// mode), and `.transfer()` throws `TypeError: ArrayBuffer is immutable`.
///
/// Calling this on an already-immutable buffer is a no-op. Calling it on
/// a detached buffer is a no-op (QuickJS returns -1 internally). The flag
/// is checked at write/transfer time, not at create time, so the buffer
/// can be initialised with bytes before being sealed.
/// Create a fresh, **immutable** `ArrayBuffer` that shares storage with
/// `source` at `[offset..offset+len]` without copying any bytes. The
/// returned buffer holds a dup'd reference to the source's `JSValue`, so
/// the backing allocation stays alive exactly as long as any view (or
/// transferred descendant of it) is reachable.
///
/// Immutability is what makes this sound:
///
/// * Writes through `Uint8Array` / `DataView` views silently no-op
/// (strict mode: `TypeError`) — aliased consumers can't corrupt the
/// source.
/// * `buffer.transfer()` throws `TypeError: ArrayBuffer is immutable`
/// — so a consumer can't detach the view and drop the `opaque`
/// pointer that keeps the source alive. Without this guard the
/// `free_func` would later fire with `opaque=NULL` (QuickJS strips
/// `opaque` on transfer; see `js_array_buffer_constructor3`) and
/// panic in `Box::from_raw(null)`. Because immutability blocks
/// transfer at the JS layer, that path is unreachable.
///
/// If a future caller wants a *mutable* shared view, they need a
/// different cleanup strategy (ptr-keyed side table, upstream QuickJS
/// patch, or accepting a per-transfer leak).