github.com/primecitizens/pcz/std@v0.2.1/ffi/js/bindings/ffi_bindings.ts (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright 2023 The Prime Citizens
     3  
     4  import { importModule, heap, Application } from "@ffi";
     5  
     6  importModule("ffi/js", (A: Application): Record<string, Function> => {
     7    return {
     8      //
     9      // Heap management
    10      //
    11      "once": (ref: heap.Ref<any>): void => {
    12        A.H.freeAfterNGets(ref, 1);
    13      },
    14      "clone": (ref: heap.Ref<any>): heap.Ref<any> => {
    15        return A.H.push(A.H.get(ref));
    16      },
    17      "free": (ref: heap.Ref<any>): void => {
    18        A.H.take(ref);
    19      },
    20      "batchFree": (ptr: number, n: number): void => {
    21        for (let i = 0; i < n; i++) {
    22          A.H.free(A.load.Uint32(ptr + i * 4));
    23        }
    24      },
    25      "replace": (old: heap.Ref<any>, ne: heap.Ref<any>): heap.Ref<boolean> => {
    26        return A.H.replace(old, A.H.take(ne));
    27      },
    28      "replaceNum": (old: heap.Ref<any>, num: number): heap.Ref<boolean> => {
    29        return A.H.replace(old, num);
    30      },
    31      "replaceBigInt": (old: heap.Ref<any>, signed: heap.Ref<boolean>, ptr: number): heap.Ref<boolean> => {
    32        return signed === A.H.TRUE ? A.H.replace(old, A.load.Int64(ptr)) : A.H.replace(old, A.load.Uint64(ptr));
    33      },
    34      "replaceBool": (old: heap.Ref<any>, bool: heap.Ref<boolean>): heap.Ref<boolean> => {
    35        return A.H.replace(old, bool === A.H.TRUE ? true : false);
    36      },
    37      "replaceString": (old: heap.Ref<any>, ptr: number, sz: number): heap.Ref<boolean> => {
    38        return A.H.replace(old, A.load.String(ptr, sz));
    39      },
    40  
    41      //
    42      // Number
    43      //
    44      "number": (n: number): heap.Ref<number> => {
    45        return A.H.push(n);
    46      },
    47      "getnum": (ref: heap.Ref<number>, ptr: number): heap.Ref<boolean> => {
    48        const x = A.H.get<number>(ref);
    49        if (typeof x !== "number") return A.H.FALSE;
    50        A.store.Float64(ptr, x);
    51        return A.H.TRUE;
    52      },
    53      "bigint": (signed: heap.Ref<boolean>, ptr: number): heap.Ref<number> => {
    54        return signed === A.H.TRUE ? A.H.push(A.load.Int64(ptr)) : A.H.push(A.load.Uint64(ptr));
    55      },
    56      "getBigInt": (ref: heap.Ref<bigint>, signed: heap.Ref<boolean>, ptr: number): heap.Ref<boolean> => {
    57        const x = A.H.get<bigint | number>(ref);
    58        // TODO: do we actually want to limit the type to BigInt?
    59        //       it seems most of the time when the WebIDL expects a int64
    60        //       js runtime only provides a "number" rather than BigInt.
    61        // if (typeof x !== "bigint") return A.H.FALSE;
    62        if (signed === A.H.TRUE) {
    63          A.store.Int64(ptr, x);
    64        } else {
    65          if (x < 0) {
    66            throw new Error("unexpected negative uint64 value");
    67          }
    68          A.store.Uint64(ptr, x);
    69        }
    70        return A.H.TRUE;
    71      },
    72  
    73      //
    74      // String
    75      //
    76      "encodeUTF8": (s: heap.Ref<string>, ptr: number, len: number): number => {
    77        return A.store.String(ptr, len, A.H.get<string>(s)).n;
    78      },
    79      "decodeUTF8": (ptr: number, len: number): heap.Ref<string> => {
    80        return A.H.push(A.load.String(ptr, len));
    81      },
    82      "appendUTF8": (s: heap.Ref<string>, strArr: number, count: number): heap.Ref<string> => {
    83        if (count === 0) {
    84          return s;
    85        }
    86  
    87        const orig = A.H.get<string>(s);
    88        if (count > 1) {
    89          count++;
    90          const buf = new Array<string>(count);
    91          buf[0] = orig;
    92          for (let i = 1; i < count; i++) {
    93            const ptr = A.load.Uint64(strArr);
    94            const len = A.load.Uint64(strArr + 8);
    95            strArr += 16;
    96            buf[i] = A.load.String(ptr, len);
    97          }
    98  
    99          return A.H.replace(s, buf.join(""));
   100        } else {
   101          return A.H.replace(s, orig + A.load.String(A.load.Uint64(strArr), A.load.Uint64(strArr + 8)));
   102        }
   103      },
   104      "appendString": (
   105        s: heap.Ref<string>,
   106        take_: heap.Ref<boolean>,
   107        strArr: number,
   108        count: number
   109      ): heap.Ref<string> => {
   110        if (count === 0) {
   111          return s;
   112        }
   113  
   114        const take = take_ === A.H.TRUE;
   115        const orig = A.H.get<string>(s);
   116        if (count > 1) {
   117          count += 1;
   118          const buf = new Array<string>(count);
   119          buf[0] = orig;
   120          for (let i = 1; i < count; i++) {
   121            buf[i] = A.load.Ref<string>(strArr, "", take);
   122            strArr += 4;
   123          }
   124  
   125          return A.H.replace(s, buf.join(""));
   126        } else {
   127          return A.H.replace(s, A.load.Ref<string>(strArr, "", take) + orig);
   128        }
   129      },
   130      "prependUTF8": (s: heap.Ref<string>, strArr: number, count: number): heap.Ref<string> => {
   131        if (count === 0) {
   132          return s;
   133        }
   134  
   135        const orig = A.H.get<string>(s);
   136        if (count > 1) {
   137          const buf = new Array<string>(count + 1);
   138          buf[count] = orig;
   139          for (let i = 0; i < count; i++) {
   140            const ptr = A.load.Uint64(strArr);
   141            const len = A.load.Uint64(strArr + 8);
   142            strArr += 16;
   143            buf[i] = A.load.String(ptr, len);
   144          }
   145  
   146          return A.H.replace(s, buf.join(""));
   147        } else {
   148          return A.H.replace(s, A.load.String(A.load.Uint64(strArr), A.load.Uint64(strArr + 8)) + orig);
   149        }
   150      },
   151      "prependString": (
   152        s: heap.Ref<string>,
   153        take_: heap.Ref<boolean>,
   154        strArr: number,
   155        count: number
   156      ): heap.Ref<string> => {
   157        if (count === 0) {
   158          return s;
   159        }
   160  
   161        const take = take_ === A.H.TRUE;
   162        const orig = A.H.get<string>(s);
   163        if (count > 1) {
   164          const buf = new Array<string>(count + 1);
   165          buf[count] = orig;
   166          for (let i = 0; i < count; i++) {
   167            buf[i] = A.load.Ref<string>(strArr, "", take);
   168            strArr += 4;
   169          }
   170  
   171          return A.H.replace(s, buf.join(""));
   172        } else {
   173          return A.H.replace(s, A.load.Ref<string>(strArr, "", take) + orig);
   174        }
   175      },
   176      "equalsUTF8": (s: heap.Ref<string>, ptr: number, len: number): heap.Ref<boolean> => {
   177        return A.load.String(ptr, len) === A.H.get<string>(s) ? A.H.TRUE : A.H.FALSE;
   178      },
   179      "sizeUTF8": (s: heap.Ref<string>): number => {
   180        return A.UTF8Sizeof(A.H.get<string>(s));
   181      },
   182  
   183      //
   184      // Func
   185      //
   186  
   187      "try": (
   188        fn: heap.Ref<Function>,
   189        self: heap.Ref<any>,
   190        free: heap.Ref<boolean>,
   191        _catch: heap.Ref<Function>,
   192        _finally: heap.Ref<Function>,
   193        ptr: number,
   194        n: number,
   195        pCaught: number
   196      ): heap.Ref<any> => {
   197        const thiz = A.H.get(self);
   198        const args = A.load.Refs(ptr, n, free === A.H.TRUE);
   199        const katch = free === A.H.TRUE ? A.H.take<Function>(_catch) : A.H.get<Function>(_catch);
   200        const vinally = free === A.H.TRUE ? A.H.take<Function>(_finally) : A.H.get<Function>(_finally);
   201  
   202        try {
   203          return A.H.push(Reflect.apply(A.H.get<Function>(fn), thiz, args));
   204        } catch (error) {
   205          A.store.Bool(pCaught, true);
   206  
   207          if (katch) {
   208            return A.H.push(Reflect.apply(katch, thiz, [error, ...args]));
   209          }
   210          return A.H.UNDEFINED;
   211        } finally {
   212          if (vinally) {
   213            Reflect.apply(vinally, thiz, args);
   214          }
   215        }
   216      },
   217      "call": (
   218        fn: heap.Ref<Function>,
   219        self: heap.Ref<any>,
   220        free: heap.Ref<boolean>,
   221        ptr: number,
   222        n: number
   223      ): heap.Ref<any> => {
   224        return A.H.push(Reflect.apply(A.H.get<Function>(fn), A.H.get(self), A.load.Refs(ptr, n, free === A.H.TRUE)));
   225      },
   226      "callVoid": (
   227        fn: heap.Ref<Function>,
   228        self: heap.Ref<any>,
   229        free: heap.Ref<boolean>,
   230        ptr: number,
   231        n: number
   232      ): void => {
   233        Reflect.apply(A.H.get<Function>(fn), A.H.get(self), A.load.Refs(ptr, n, free === A.H.TRUE));
   234      },
   235      "callNum": (
   236        fn: heap.Ref<Function>,
   237        self: heap.Ref<any>,
   238        free: heap.Ref<boolean>,
   239        ptr: number,
   240        n: number
   241      ): number => {
   242        return Reflect.apply(A.H.get<Function>(fn), A.H.get(self), A.load.Refs(ptr, n, free === A.H.TRUE)) as number;
   243      },
   244      "callBool": (
   245        fn: heap.Ref<Function>,
   246        self: heap.Ref<any>,
   247        free: heap.Ref<boolean>,
   248        ptr: number,
   249        n: number
   250      ): heap.Ref<boolean> => {
   251        return Reflect.apply(A.H.get<Function>(fn), A.H.get(self), A.load.Refs(ptr, n, free === A.H.TRUE))
   252          ? A.H.TRUE
   253          : A.H.FALSE;
   254      },
   255  
   256      //
   257      // Object
   258      //
   259      "new": (constructor: heap.Ref<Function>, free: heap.Ref<boolean>, ptr: number, n: number): heap.Ref<any> => {
   260        return A.H.push(Reflect.construct(A.H.get(constructor), A.load.Refs(ptr, n, free === A.H.TRUE)));
   261      },
   262      "instanceof": (a: heap.Ref<any>, cls: heap.Ref<any>): heap.Ref<boolean> => {
   263        return A.H.get<any>(a) instanceof A.H.get<any>(cls) ? A.H.TRUE : A.H.FALSE;
   264      },
   265  
   266      "getPrototype": (self: heap.Ref<object>): heap.Ref<object> => {
   267        const ret = Reflect.getPrototypeOf(A.H.get<object>(self));
   268        if (ret) {
   269          return A.H.push(ret);
   270        }
   271        return A.H.UNDEFINED;
   272      },
   273      "setPrototype": (
   274        self: heap.Ref<object>,
   275        free: heap.Ref<object>,
   276        prototype: heap.Ref<object>
   277      ): heap.Ref<boolean> => {
   278        const proto = free === A.H.TRUE ? A.H.take<object>(prototype) : A.H.get<object>(prototype);
   279        return Reflect.setPrototypeOf(A.H.get<object>(self), proto) ? A.H.TRUE : A.H.FALSE;
   280      },
   281  
   282      "getPropDesc": (self: heap.Ref<object>, ptr: number, sz: number): number => {
   283        const desc = Reflect.getOwnPropertyDescriptor(A.H.get<object>(self), A.load.String(ptr, sz));
   284        if (!desc) {
   285          return 0;
   286        }
   287        // NOTE: MUST agree with ffi/wasm/js/object.go#PropertyDescription_xxx
   288        let flags: number = 1;
   289        flags += desc.writable ? 2 : 0;
   290        flags += desc.configurable ? 4 : 0;
   291        flags += desc.enumerable ? 8 : 0;
   292        flags += desc.get ? 16 : 0;
   293        flags += desc.set ? 32 : 0;
   294        return flags;
   295      },
   296      "defineProp": (
   297        self: heap.Ref<object>,
   298        ptr: number,
   299        sz: number,
   300        flags: number,
   301        getter: heap.Ref<Function>,
   302        setter: heap.Ref<Function>
   303      ): heap.Ref<boolean> => {
   304        return Reflect.defineProperty(A.H.get<object>(self), A.load.String(ptr, sz), {
   305          writable: (flags & 2) !== 0 ? true : false,
   306          configurable: (flags & 4) !== 0 ? true : false,
   307          enumerable: (flags & 8) !== 0 ? true : false,
   308          get: (flags & 16) !== 0 ? (A.H.get<Function>(getter) as () => any) : undefined,
   309          set: (flags & 32) !== 0 ? (A.H.get<Function>(setter) as (v: any) => void) : undefined,
   310        })
   311          ? A.H.TRUE
   312          : A.H.FALSE;
   313      },
   314      "deleteProp": (self: heap.Ref<Object>, ptr: number, sz: number): heap.Ref<boolean> => {
   315        return Reflect.deleteProperty(A.H.get<object>(self), A.load.String(ptr, sz)) ? A.H.TRUE : A.H.FALSE;
   316      },
   317      "prop": (self: heap.Ref<Object>, ptr: number, sz: number): heap.Ref<any> => {
   318        const thiz = A.H.get<object>(self);
   319        return A.H.push(Reflect.get(thiz, A.load.String(ptr, sz), thiz));
   320      },
   321      "numProp": (self: heap.Ref<Object>, ptr: number, sz: number): number => {
   322        const thiz = A.H.get<object>(self);
   323        return Reflect.get(thiz, A.load.String(ptr, sz), thiz) as number;
   324      },
   325      "boolProp": (self: heap.Ref<Object>, ptr: number, sz: number): heap.Ref<boolean> => {
   326        const thiz = A.H.get<object>(self);
   327        return Reflect.get(thiz, A.load.String(ptr, sz), thiz) ? A.H.TRUE : A.H.FALSE;
   328      },
   329      "propByString": (self: heap.Ref<Object>, name: heap.Ref<string>): heap.Ref<any> => {
   330        const thiz = A.H.get<object>(self);
   331        return A.H.push(Reflect.get(thiz, A.H.get<string>(name), thiz));
   332      },
   333      "numPropByString": (self: heap.Ref<Object>, name: heap.Ref<string>): number => {
   334        const thiz = A.H.get<object>(self);
   335        return Reflect.get(thiz, A.H.get<string>(name), thiz) as number;
   336      },
   337      "boolPropByString": (self: heap.Ref<Object>, name: heap.Ref<string>): heap.Ref<boolean> => {
   338        const thiz = A.H.get<object>(self);
   339        return Reflect.get(thiz, A.H.get<string>(name), thiz) ? A.H.TRUE : A.H.FALSE;
   340      },
   341  
   342      "setProp": (
   343        self: heap.Ref<Object>,
   344        ptr: number,
   345        sz: number,
   346        free: heap.Ref<boolean>,
   347        val: heap.Ref<any>
   348      ): heap.Ref<boolean> => {
   349        const thiz = A.H.get<object>(self);
   350        return Reflect.set(thiz, A.load.String(ptr, sz), free === A.H.TRUE ? A.H.take(val) : A.H.get(val), thiz)
   351          ? A.H.TRUE
   352          : A.H.FALSE;
   353      },
   354      "setNumProp": (self: heap.Ref<Object>, ptr: number, sz: number, val: number): heap.Ref<boolean> => {
   355        const thiz = A.H.get<object>(self);
   356        return Reflect.set(thiz, A.load.String(ptr, sz), val, thiz) ? A.H.TRUE : A.H.FALSE;
   357      },
   358      "setBoolProp": (self: heap.Ref<Object>, ptr: number, sz: number, val: heap.Ref<boolean>): heap.Ref<boolean> => {
   359        const thiz = A.H.get<object>(self);
   360        return Reflect.set(thiz, A.load.String(ptr, sz), val === A.H.TRUE ? true : false, thiz) ? A.H.TRUE : A.H.FALSE;
   361      },
   362      "setStringProp": (
   363        self: heap.Ref<Object>,
   364        nameptr: number,
   365        namesz: number,
   366        valptr: number,
   367        valsz: number
   368      ): heap.Ref<boolean> => {
   369        const thiz = A.H.get<object>(self);
   370        return Reflect.set(thiz, A.load.String(nameptr, namesz), A.load.String(valptr, valsz), thiz)
   371          ? A.H.TRUE
   372          : A.H.FALSE;
   373      },
   374      "setPropByString": (
   375        self: heap.Ref<Object>,
   376        name: heap.Ref<string>,
   377        free: heap.Ref<boolean>,
   378        val: heap.Ref<any>
   379      ): heap.Ref<boolean> => {
   380        const thiz = A.H.get<object>(self);
   381        return Reflect.set(thiz, A.H.get<string>(name), free === A.H.TRUE ? A.H.take(val) : A.H.get(val), thiz)
   382          ? A.H.TRUE
   383          : A.H.FALSE;
   384      },
   385      "setNumPropByString": (self: heap.Ref<Object>, name: heap.Ref<string>, val: number): heap.Ref<boolean> => {
   386        const thiz = A.H.get<object>(self);
   387        return Reflect.set(thiz, A.H.get<string>(name), val, thiz) ? A.H.TRUE : A.H.FALSE;
   388      },
   389      "setBoolPropByString": (self: heap.Ref<Object>, name: heap.Ref<string>, val: number): heap.Ref<boolean> => {
   390        const thiz = A.H.get<object>(self);
   391        return Reflect.set(thiz, A.H.get<string>(name), val === A.H.TRUE ? true : false, thiz) ? A.H.TRUE : A.H.FALSE;
   392      },
   393      "setStringPropByString": (
   394        self: heap.Ref<Object>,
   395        name: heap.Ref<string>,
   396        free: heap.Ref<boolean>,
   397        val: heap.Ref<string>
   398      ): heap.Ref<boolean> => {
   399        const thiz = A.H.get<object>(self);
   400        return Reflect.set(thiz, A.H.get<string>(name), free === A.H.TRUE ? A.H.take(val) : A.H.get<string>(val), thiz)
   401          ? A.H.TRUE
   402          : A.H.FALSE;
   403      },
   404    };
   405  });