You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -44,44 +44,149 @@ It is important to understand the ownership, and threading concerns around such
44
44
45
45
## Ownership
46
46
47
-
- An `ArrayBuffer` that was created on the native side is **owning**, which means you can safely access it's data as long as the `ArrayBuffer` reference is alive.
47
+
There's two types of `ArrayBuffer`s, **owning** and **non-owning**:
48
+
49
+
### Owning
50
+
51
+
An `ArrayBuffer` that was created on the native side is **owning**, which means you can safely access it's data as long as the `ArrayBuffer` reference is alive.
48
52
It can be safely held strong for longer, e.g. as a class property/member, and accessed from different Threads.
49
53
50
-
```swift
51
-
funcdoSomething() -> ArrayBufferHolder {
52
-
let buffer = ArrayBufferHolder.allocate(1024*10)
53
-
let data = buffer.data// <-- ✅ safe to do because we own it!
54
-
self.buffer= buffer // <-- ✅ safe to do to use it later!
55
-
DispatchQueue.global().async {
56
-
let data = buffer.data// <-- ✅ also safe because we own it!
57
-
}
58
-
return buffer
54
+
```swift
55
+
funcdoSomething() -> ArrayBufferHolder {
56
+
// highlight-next-line
57
+
let buffer = ArrayBufferHolder.allocate(1024*10)
58
+
let data = buffer.data// <-- ✅ safe to do because we own it!
59
+
self.buffer= buffer // <-- ✅ safe to use it later!
60
+
DispatchQueue.global().async {
61
+
let data = buffer.data// <-- ✅ also safe because we own it!
59
62
}
60
-
```
63
+
return buffer
64
+
}
65
+
```
66
+
67
+
### Non-owning
61
68
62
-
-An `ArrayBuffer` that was received as a parameter from JS cannot be safely kept strong as the JS VM can delete it at any point, hence it is **non-owning**.
69
+
An `ArrayBuffer` that was received as a parameter from JS cannot be safely kept strong as the JS VM can delete it at any point, hence it is **non-owning**.
63
70
It's data can only be safely accessed before the synchronous function returned, as this will stay within the JS bounds.
64
71
65
-
```swift
66
-
funcdoSomething(buffer: ArrayBufferHolder) {
67
-
let data = buffer.data// <-- ✅ safe to do because we're still sync
68
-
DispatchQueue.global().async {
69
-
// code-error
70
-
let data = buffer.data// <-- ❌ NOT safe
71
-
}
72
+
```swift
73
+
funcdoSomething(buffer: ArrayBufferHolder) {
74
+
let data = buffer.data// <-- ✅ safe to do because we're still sync
75
+
DispatchQueue.global().async {
76
+
// code-error
77
+
let data = buffer.data// <-- ❌ NOT safe
72
78
}
73
-
```
74
-
If you need a non-owning buffer's data for longer, **copy it first**:
75
-
```swift
76
-
funcdoSomething(buffer: ArrayBufferHolder) {
77
-
let copy = ArrayBufferHolder.copy(of: buffer)
78
-
DispatchQueue.global().async {
79
-
let data = copy.data// <-- ✅ safe now because we have a owning copy
80
-
}
79
+
}
80
+
```
81
+
If you need a non-owning buffer's data for longer, **copy it first**:
82
+
```swift
83
+
funcdoSomething(buffer: ArrayBufferHolder) {
84
+
// diff-add
85
+
let copy = ArrayBufferHolder.copy(of: buffer)
86
+
let data = copy.data// <-- ✅ safe now because we have a owning copy
87
+
DispatchQueue.global().async {
88
+
let data = copy.data// <-- ✅ still safe now because we have a owning copy
81
89
}
82
-
```
90
+
}
91
+
```
83
92
84
93
## Threading
85
94
86
95
An `ArrayBuffer` can be accessed from both JS and native, and even from multiple Threads at once, but they are **not thread-safe**.
87
96
To prevent race conditions or garbage-data from being read, make sure to not read from- and write to- the `ArrayBuffer` at the same time.
97
+
98
+
## Creating Buffers
99
+
100
+
Buffers can either be created from native (**owning**), or from JS (**non-owning**).
101
+
102
+
### From native
103
+
104
+
On the native side, an **owning**`ArrayBuffer` can either **wrap-**, or **copy-** an existing buffer:
105
+
106
+
<Tabs>
107
+
<TabItemvalue="cpp"label="C++">
108
+
```cpp
109
+
auto myData = new uint8_t*[4096];
110
+
111
+
// wrap (no copy)
112
+
auto wrappingArrayBuffer = ArrayBuffer::wrap(myData, 4096, [=]() {
113
+
delete[] myData;
114
+
});
115
+
// copy
116
+
auto copiedArrayBuffer = ArrayBuffer::copy(myData, 4096);
117
+
// new blank buffer
118
+
auto newArrayBuffer = ArrayBuffer::allocate(4096);
119
+
```
120
+
</TabItem>
121
+
<TabItemvalue="swift"label="Swift">
122
+
```swift
123
+
let myData = UnsafeMutablePointer<UInt8>.allocate(capacity: 4096)
124
+
125
+
// wrap (no copy)
126
+
let wrappingArrayBuffer = ArrayBuffer.wrap(dataWithoutCopy: myData,
127
+
size: 4096,
128
+
onDelete: { myData.deallocate() })
129
+
// copy
130
+
let copiedArrayBuffer = ArrayBuffer.copy(of: wrappingArrayBuffer)
131
+
// new blank buffer
132
+
let newArrayBuffer = ArrayBuffer.allocate(size: 4096)
133
+
```
134
+
</TabItem>
135
+
<TabItemvalue="kotlin"label="Kotlin">
136
+
```kotlin
137
+
val myData = ByteBuffer.allocateDirect(4096)
138
+
139
+
// wrap (no copy)
140
+
val wrappingArrayBuffer = ArrayBuffer.wrap(myData)
141
+
142
+
143
+
// copy
144
+
let copiedArrayBuffer = ArrayBuffer.copy(myData)
145
+
// new blank buffer
146
+
val newArrayBuffer = ArrayBuffer.allocate(4096)
147
+
```
148
+
</TabItem>
149
+
</Tabs>
150
+
151
+
#### Language-native buffer types
152
+
153
+
ArrayBuffers also provide helper and conversion methods for the language-native conventional buffer types:
154
+
155
+
<Tabs>
156
+
<TabItemvalue="cpp"label="C++">
157
+
C++ often uses [`std::vector<uint8_t>`](https://en.cppreference.com/w/cpp/container/vector) to represent Data.
158
+
```cpp
159
+
std::vector<uint8_t> data;
160
+
auto buffer = ArrayBuffer::copy(data);
161
+
/* convert back to vector would be a copy. */
162
+
```
163
+
</TabItem>
164
+
<TabItemvalue="swift"label="Swift">
165
+
Swift often uses [`Data`](https://developer.apple.com/documentation/foundation/data) to represent Data.
166
+
```swift
167
+
let data = Data(capacity: 1024)
168
+
let buffer = ArrayBufferHolder.copy(data: data)
169
+
let dataAgain = buffer.toData(copyIfNeeded: true)
170
+
```
171
+
</TabItem>
172
+
<TabItemvalue="kotlin"label="Kotlin">
173
+
Kotlin often uses [`ByteBuffer`](https://developer.android.com/reference/java/nio/ByteBuffer) to represent Data.
174
+
```kotlin
175
+
val data = ByteBuffer.allocateDirect(1024)
176
+
val buffer = ArrayBuffer.copy(data)
177
+
val dataAgain = buffer.getBuffer(copyIfNeeded = true)
178
+
```
179
+
</TabItem>
180
+
</Tabs>
181
+
182
+
### From JS
183
+
184
+
From JS, a **non-owning**`ArrayBuffer` can be created via the [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) web APIs, and viewed or edited using the typed array APIs (e.g. [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)).
0 commit comments