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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// 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).