github.com/primecitizens/pcz/std@v0.2.1/ffi/js/array/ffi_bindings.ts (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright 2023 The Prime Citizens 3 4 import { Application, Pointer, heap, importModule } from "@ffi"; 5 6 importModule("ffi/js/array", (A: Application) => { 7 type TypedArray = 8 | Uint16Array 9 | Int16Array 10 | Uint32Array 11 | Int32Array 12 | Float32Array 13 | Float64Array 14 | BigUint64Array 15 | BigInt64Array; 16 17 // append go numeric values to js array. 18 const append = ( 19 load: (ptr: number) => number | bigint, 20 elemSz: number, 21 refJsArray: heap.Ref<TypedArray>, 22 offsetInJsArray: number, 23 goArray: Pointer, 24 goArrayLen: number 25 ): number => { 26 const jsArray = A.H.get<TypedArray>(refJsArray); 27 28 if (jsArray.length <= offsetInJsArray) return 0; 29 30 const cap = jsArray.length - offsetInJsArray; 31 if (cap < goArrayLen) { 32 goArrayLen = cap; 33 } 34 35 for (let i = offsetInJsArray; i < goArrayLen; i++) { 36 jsArray[i] = load(goArray + i * elemSz); 37 } 38 return goArrayLen; 39 }; 40 41 // copy js numeric values in array to go array. 42 const copy = ( 43 store: (ptr: number, val: number | bigint) => void, 44 elemSz: number, 45 refJsArray: heap.Ref<TypedArray>, 46 offsetInJsArray: number, 47 goArray: Pointer, 48 goArrayLen: number 49 ): number => { 50 const jsArray = A.H.get<TypedArray>(refJsArray); 51 52 if (jsArray.length <= offsetInJsArray) return 0; 53 54 const cap = jsArray.length - offsetInJsArray; 55 if (cap < goArrayLen) { 56 goArrayLen = cap; 57 } 58 59 for (let i = offsetInJsArray; i < goArrayLen; i++) { 60 store(goArray + i * elemSz, jsArray[i]); 61 } 62 return goArrayLen; 63 }; 64 65 return { 66 // 67 // Array 68 // 69 "new": ( 70 sz: number, 71 elemSz: number, 72 signed: heap.Ref<boolean>, 73 float: heap.Ref<boolean> 74 ): heap.Ref<Array<any> | TypedArray> => { 75 switch (elemSz) { 76 case 0: 77 return A.H.push(new Array(sz)); 78 case 1: 79 return signed === A.H.TRUE ? A.H.push(new Int8Array(sz)) : A.H.push(new Uint8Array(sz)); 80 case 2: 81 return signed === A.H.TRUE ? A.H.push(new Int16Array(sz)) : A.H.push(new Uint16Array(sz)); 82 case 4: 83 if (float === A.H.TRUE) return A.H.push(new Float32Array(sz)); 84 85 return signed === A.H.TRUE ? A.H.push(new Int32Array(sz)) : A.H.push(new Uint32Array(sz)); 86 case 8: 87 if (float === A.H.TRUE) return A.H.push(new Float64Array(sz)); 88 89 // available since ES2020 90 return signed === A.H.TRUE ? A.H.push(new BigInt64Array(sz)) : A.H.push(new BigUint64Array(sz)); 91 default: 92 throw new Error(`unsupported element size=${elemSz}`); 93 } 94 }, 95 "length": (arr: heap.Ref<Array<any> | TypedArray>): number => { 96 return A.H.get<Array<any> | TypedArray>(arr).length; 97 }, 98 "slice": ( 99 arr: heap.Ref<Array<any> | TypedArray>, 100 start: number, 101 end: number 102 ): heap.Ref<Array<any> | TypedArray> => { 103 if (end) { 104 return A.H.push(A.H.get<Array<any> | TypedArray>(arr).slice(start, end)); 105 } 106 107 return A.H.push(A.H.get<Array<any> | TypedArray>(arr).slice(start)); 108 }, 109 "append": ( 110 refJsArray: heap.Ref<Array<any> | TypedArray>, 111 take: heap.Ref<boolean>, 112 elemSz: number, 113 signed: heap.Ref<boolean>, 114 float: heap.Ref<boolean>, 115 offsetInJsArray: number, 116 goArray: Pointer, 117 goArrayLen: number 118 ): number => { 119 switch (elemSz) { 120 case 0: { 121 let data = A.load.Refs(goArray, goArrayLen, take === A.H.TRUE); 122 const a = A.H.get<Array<any>>(refJsArray); 123 let j = 0; 124 for (let i = offsetInJsArray; i < a.length && j < data.length; i++) { 125 a[i] = data[j]; 126 j++; 127 } 128 A.H.replace(refJsArray, a.concat(data.slice(j))); 129 return goArrayLen; 130 } 131 case 1: { 132 const a = A.H.get<Int8Array | Uint8Array | Uint8ClampedArray>(refJsArray); 133 if (a.length <= offsetInJsArray) return 0; 134 const cap = a.length - offsetInJsArray; 135 if (cap < goArrayLen) goArrayLen = cap; 136 a.set(A.load.Raw(goArray, goArrayLen), offsetInJsArray); 137 return goArrayLen; 138 } 139 case 2: 140 return signed === A.H.TRUE 141 ? append(A.load.Int16, 2, refJsArray, offsetInJsArray, goArray, goArrayLen) 142 : append(A.load.Uint16, 2, refJsArray, offsetInJsArray, goArray, goArrayLen); 143 case 4: 144 if (float === A.H.TRUE) return append(A.load.Float32, 4, refJsArray, offsetInJsArray, goArray, goArrayLen); 145 146 return signed === A.H.TRUE 147 ? append(A.load.Int32, 4, refJsArray, offsetInJsArray, goArray, goArrayLen) 148 : append(A.load.Uint32, 4, refJsArray, offsetInJsArray, goArray, goArrayLen); 149 case 8: 150 if (float === A.H.TRUE) return append(A.load.Float64, 8, refJsArray, offsetInJsArray, goArray, goArrayLen); 151 152 return signed === A.H.TRUE 153 ? append(A.load.Int64, 8, refJsArray, offsetInJsArray, goArray, goArrayLen) 154 : append(A.load.Uint64, 8, refJsArray, offsetInJsArray, goArray, goArrayLen); 155 default: 156 throw new Error(`unsupported element size=${elemSz}`); 157 } 158 }, 159 "copy": ( 160 refJsArray: heap.Ref<Array<any> | TypedArray>, 161 elemSz: number, 162 signed: heap.Ref<boolean>, 163 float: heap.Ref<boolean>, 164 offsetInJsArray: number, 165 goArray: Pointer, 166 goArrayLen: number 167 ): number => { 168 switch (elemSz) { 169 case 1: 170 const a = A.H.get<Int8Array | Uint8Array | Uint8ClampedArray>(refJsArray); 171 if (a.length <= offsetInJsArray) return 0; 172 const cap = a.length - offsetInJsArray; 173 if (cap < goArrayLen) goArrayLen = cap; 174 A.load.Raw(goArray, goArrayLen).set(a, offsetInJsArray); 175 return goArrayLen; 176 case 2: 177 return signed === A.H.TRUE 178 ? copy(A.store.Int16, 2, refJsArray, offsetInJsArray, goArray, goArrayLen) 179 : copy(A.store.Uint16, 2, refJsArray, offsetInJsArray, goArray, goArrayLen); 180 case 4: 181 if (float === A.H.TRUE) return copy(A.store.Float32, 4, refJsArray, offsetInJsArray, goArray, goArrayLen); 182 183 return signed === A.H.TRUE 184 ? copy(A.store.Int32, 4, refJsArray, offsetInJsArray, goArray, goArrayLen) 185 : copy(A.store.Uint32, 4, refJsArray, offsetInJsArray, goArray, goArrayLen); 186 case 8: 187 if (float === A.H.TRUE) return copy(A.store.Float64, 8, refJsArray, offsetInJsArray, goArray, goArrayLen); 188 189 return signed === A.H.TRUE 190 ? copy(A.store.Int64, 8, refJsArray, offsetInJsArray, goArray, goArrayLen) 191 : copy(A.store.Uint64, 8, refJsArray, offsetInJsArray, goArray, goArrayLen); 192 default: 193 throw new Error(`unsupported element size=${elemSz}`); 194 } 195 }, 196 "set": (a: heap.Ref<TypedArray>, b: heap.Ref<TypedArray>): void => { 197 A.H.get<Uint32Array>(a).set(A.H.get<Uint32Array>(b)); 198 }, 199 "buffer": (take: heap.Ref<boolean>, ref: heap.Ref<TypedArray>): heap.Ref<ArrayBufferLike> => { 200 return A.H.push((take === A.H.TRUE ? A.H.take<TypedArray>(ref) : A.H.get<TypedArray>(ref)).buffer); 201 }, 202 "fromBuffer": ( 203 take: heap.Ref<boolean>, 204 refBuf: heap.Ref<ArrayBuffer | SharedArrayBuffer>, 205 elemSz: number, 206 signed: heap.Ref<boolean>, 207 float: heap.Ref<boolean> 208 ): heap.Ref<TypedArray> => { 209 const buf = (take === A.H.TRUE ? A.H.take(refBuf) : A.H.get(refBuf)) as ArrayBuffer; 210 switch (elemSz) { 211 case 1: 212 return signed === A.H.TRUE ? A.H.push(new Int8Array(buf)) : A.H.push(new Uint8Array(buf)); 213 case 2: 214 return signed === A.H.TRUE ? A.H.push(new Int16Array(buf)) : A.H.push(new Uint16Array(buf)); 215 case 4: 216 if (float === A.H.TRUE) return A.H.push(new Float32Array(buf)); 217 218 return signed === A.H.TRUE ? A.H.push(new Int32Array(buf)) : A.H.push(new Uint32Array(buf)); 219 case 8: 220 if (float === A.H.TRUE) return A.H.push(new Float64Array(buf)); 221 222 return signed === A.H.TRUE ? A.H.push(new BigInt64Array(buf)) : A.H.push(new BigUint64Array(buf)); 223 default: 224 throw new Error(`unsupported element size=${elemSz}`); 225 } 226 }, 227 "byteOffset": (ref: heap.Ref<TypedArray>): number => { 228 return A.H.get<TypedArray>(ref).byteOffset; 229 }, 230 "byteLength": (ref: heap.Ref<TypedArray>): number => { 231 return A.H.get<TypedArray>(ref).byteLength; 232 }, 233 "nth": ( 234 self: heap.Ref<Array<any>>, 235 elemSz: number, 236 signed: heap.Ref<boolean>, 237 float: heap.Ref<boolean>, 238 i: number, 239 ptr: number 240 ): heap.Ref<any> => { 241 const thiz = A.H.get<Array<any> | TypedArray>(self); 242 if (i >= thiz.length) return A.H.FALSE; 243 244 switch (elemSz) { 245 case 0: 246 A.store.Ref(ptr, thiz[i]); 247 break; 248 case 1: 249 if (signed === A.H.TRUE) { 250 A.store.Int8(ptr, thiz[i]); 251 } else { 252 A.store.Uint8(ptr, thiz[i]); 253 } 254 break; 255 case 2: 256 if (signed === A.H.TRUE) { 257 A.store.Int16(ptr, thiz[i]); 258 } else { 259 A.store.Uint16(ptr, thiz[i]); 260 } 261 break; 262 case 4: 263 if (float === A.H.TRUE) { 264 A.store.Float32(ptr, thiz[i]); 265 } else if (signed === A.H.TRUE) { 266 A.store.Int32(ptr, thiz[i]); 267 } else { 268 A.store.Uint32(ptr, thiz[i]); 269 } 270 break; 271 case 8: 272 if (float === A.H.TRUE) { 273 A.store.Float64(ptr, thiz[i]); 274 } else if (signed === A.H.TRUE) { 275 A.store.Int64(ptr, thiz[i]); 276 } else { 277 A.store.Uint64(ptr, thiz[i]); 278 } 279 break; 280 default: 281 throw new Error(`unsupported element size=${elemSz}`); 282 } 283 284 return A.H.TRUE; 285 }, 286 "nthNum": (self: heap.Ref<Array<any>>, i: number, ptr: number): heap.Ref<boolean> => { 287 const thiz = A.H.get<Array<any>>(self); 288 if (i >= thiz.length) return A.H.FALSE; 289 290 A.store.Float64(ptr, thiz[i]); 291 return A.H.TRUE; 292 }, 293 "nthBool": (self: heap.Ref<Array<any>>, i: number, ptr: number): heap.Ref<boolean> => { 294 const thiz = A.H.get<Array<any>>(self); 295 if (i >= thiz.length) return A.H.FALSE; 296 297 A.store.Bool(ptr, thiz[i] ? true : false); 298 return A.H.TRUE; 299 }, 300 301 "setNth": ( 302 self: heap.Ref<Array<any>>, 303 elemSz: number, 304 signed: heap.Ref<boolean>, 305 float: heap.Ref<boolean>, 306 i: number, 307 take: heap.Ref<boolean>, 308 ptr: Pointer 309 ): heap.Ref<boolean> => { 310 const thiz = A.H.get<Array<any>>(self); 311 if (i >= thiz.length) return A.H.FALSE; 312 313 switch (elemSz) { 314 case 0: 315 thiz[i] = A.load.Ref(ptr, undefined, take === A.H.TRUE); 316 break; 317 case 1: 318 if (signed === A.H.TRUE) { 319 thiz[i] = A.load.Int8(ptr); 320 } else { 321 thiz[i] = A.load.Uint8(ptr); 322 } 323 break; 324 case 2: 325 if (signed === A.H.TRUE) { 326 thiz[i] = A.load.Int16(ptr); 327 } else { 328 thiz[i] = A.load.Uint16(ptr); 329 } 330 break; 331 case 4: 332 if (float === A.H.TRUE) { 333 thiz[i] = A.load.Float32(ptr); 334 } else if (signed === A.H.TRUE) { 335 thiz[i] = A.load.Int32(ptr); 336 } else { 337 thiz[i] = A.load.Uint32(ptr); 338 } 339 break; 340 case 8: 341 if (float === A.H.TRUE) { 342 thiz[i] = A.load.Float64(ptr); 343 } else if (signed === A.H.TRUE) { 344 thiz[i] = A.load.Int64(ptr); 345 } else { 346 thiz[i] = A.load.Uint64(ptr); 347 } 348 break; 349 default: 350 throw new Error(`unsupported element size=${elemSz}`); 351 } 352 return A.H.TRUE; 353 }, 354 "setNthNum": (self: heap.Ref<Array<any>>, i: number, val: number): heap.Ref<boolean> => { 355 const thiz = A.H.get<Array<any>>(self); 356 if (i >= thiz.length) return A.H.FALSE; 357 thiz[i] = val; 358 return A.H.TRUE; 359 }, 360 "setNthBool": (self: heap.Ref<Array<any>>, i: number, val: heap.Ref<boolean>): heap.Ref<boolean> => { 361 const thiz = A.H.get<Array<any>>(self); 362 if (i >= thiz.length) return A.H.FALSE; 363 thiz[i] = val === A.H.TRUE ? true : false; 364 return A.H.TRUE; 365 }, 366 "setNthString": (self: heap.Ref<Array<any>>, i: number, ptr: number, sz: number): heap.Ref<boolean> => { 367 const thiz = A.H.get<Array<any>>(self); 368 if (i >= thiz.length) return A.H.FALSE; 369 thiz[i] = A.load.String(ptr, sz); 370 return A.H.TRUE; 371 }, 372 }; 373 });