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  });