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